diff options
58 files changed, 477 insertions, 2160 deletions
@@ -408,10 +408,6 @@ L<FS::cust_bill_pkg_detail> - Invoice line item detail class L<FS::legacy_cust_bill> - Legacy data invoice class -L<FS::part_bill_event> - (Old) Invoice event definition class - -L<FS::cust_bill_event> - (Old) Completed invoice event class - L<FS::part_event> - (New) Billing event definition class L<FS::part_event_option> - (New) Billing event option class diff --git a/FS/FS/API.pm b/FS/FS/API.pm index c49fb20..f848361 100644 --- a/FS/FS/API.pm +++ b/FS/FS/API.pm @@ -365,26 +365,6 @@ comma-separated list of email addresses for email invoices. The special value 'P postal_invoicing Set to 1 to enable postal invoicing -=item payby - -CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY - -=item payinfo - -Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL - -=item paycvv - -Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch) - -=item paydate - -Expiration date for CARD/DCRD - -=item payname - -Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK - =item referral_custnum Referring customer number @@ -505,27 +485,6 @@ addition to email addresses), postal_invoicing Set to 1 to enable postal invoicing -=item payby - -CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY - -=item payinfo - -Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid -"pin" for PREPAY, purchase order number for BILL - -=item paycvv - -Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch) - -=item paydate - -Expiration date for CARD/DCRD - -=item payname - -Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK - =item referral_custnum Referring customer number diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index f395dea..82423d8 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -53,7 +53,6 @@ assigned to users and/or groups. # 'billing' => [ # '_desc' => 'Access to billing configuration', # 'payment_gateway' => {}, -# 'part_bill_event' => {}, # 'prepay_credit' => {}, # 'rate' => {}, # 'cust_main_county' => {}, diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 091070e..bb04d94 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2147,11 +2147,6 @@ and customer address. Include units.', }, { - 'key' => 'safe-part_bill_event', - 'section' => 'UI', - 'description' => 'Validates invoice event expressions against a preset list. Useful for webdemos, annoying to powerusers.', - 'type' => 'checkbox', - }, { 'key' => 'show_ship_company', diff --git a/FS/FS/Cron/bill.pm b/FS/FS/Cron/bill.pm index 98f1c2e..a822654 100644 --- a/FS/FS/Cron/bill.pm +++ b/FS/FS/Cron/bill.pm @@ -190,8 +190,6 @@ sub bill_where { push @search, "( cust_main.archived != 'Y' OR archived IS NULL )"; #disable? - push @search, "cust_main.payby = '". $opt{'p'}. "'" - if $opt{'p'}; push @search, "cust_main.agentnum IN ( ". $opt{'a'}. " ) " if $opt{'a'}; diff --git a/FS/FS/Cron/breakage.pm b/FS/FS/Cron/breakage.pm index 6dd904d..56a9df4 100644 --- a/FS/FS/Cron/breakage.pm +++ b/FS/FS/Cron/breakage.pm @@ -47,7 +47,7 @@ sub reconcile_breakage { my @customers = qsearch({ 'table' => 'cust_main', 'hashref' => { 'agentnum' => $agent->agentnum, - 'payby' => { op=>'!=', value=>'COMP', }, + 'complimentary' => { op=>'!=', value=>'Y', }, }, 'extra_sql' => $extra_sql, }); diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 37e3ad2..81671ff 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -180,7 +180,6 @@ if ( -e $addl_handler_use_file ) { use FS::cust_pay_refund; use FS::cust_svc; use FS::nas; - use FS::part_bill_event; use FS::part_event; use FS::part_event_condition; use FS::part_pkg; diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 5333b1a..db2d3cf 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -794,58 +794,6 @@ sub tables_hashref { ], }, - #old "invoice" events, deprecated - 'cust_bill_event' => { - 'columns' => [ - 'eventnum', 'serial', '', '', '', '', - 'invnum', 'int', '', '', '', '', - 'eventpart', 'int', '', '', '', '', - '_date', @date_type, '', '', - 'status', 'varchar', '', $char_d, '', '', - 'statustext', 'text', 'NULL', '', '', '', - ], - 'primary_key' => 'eventnum', - #no... there are retries now #'unique' => [ [ 'eventpart', 'invnum' ] ], - 'unique' => [], - 'index' => [ ['invnum'], ['status'], ['eventpart'], - ['statustext'], ['_date'], - ], - 'foreign_keys' => [ - { columns => [ 'invnum' ], - table => 'cust_bill', - }, - { columns => [ 'eventpart' ], - table => 'part_bill_event', - }, - ], - }, - - #old "invoice" events, deprecated - 'part_bill_event' => { - 'columns' => [ - 'eventpart', 'serial', '', '', '', '', - 'freq', 'varchar', 'NULL', $char_d, '', '', - 'payby', 'char', '', 4, '', '', - 'event', 'varchar', '', $char_d, '', '', - 'eventcode', @perl_type, '', '', - 'seconds', 'int', 'NULL', '', '', '', - 'weight', 'int', '', '', '', '', - 'plan', 'varchar', 'NULL', $char_d, '', '', - 'plandata', 'text', 'NULL', '', '', '', - 'reason', 'int', 'NULL', '', '', '', - 'disabled', 'char', 'NULL', 1, '', '', - ], - 'primary_key' => 'eventpart', - 'unique' => [], - 'index' => [ ['payby'], ['disabled'], ], - 'foreign_keys' => [ - { columns => [ 'reason' ], - table => 'reason', - references => [ 'reasonnum' ], - }, - ], - }, - 'part_event' => { 'columns' => [ 'eventpart', 'serial', '', '', '', '', diff --git a/FS/FS/Setup.pm b/FS/FS/Setup.pm index 5528c89..f26e50e 100644 --- a/FS/FS/Setup.pm +++ b/FS/FS/Setup.pm @@ -363,13 +363,11 @@ sub initial_data { #with billing type Complimentary. Leave the First package dropdown set to #(none). 'cust_main' => [ - { 'agentnum' => 1, #XXX - 'refnum' => 1, #XXX - 'first' => 'System', - 'last' => 'Accounts', - 'payby' => 'COMP', - 'payinfo' => 'system', #or something - 'paydate' => '1/2037', + { 'agentnum' => 1, #XXX + 'refnum' => 1, #XXX + 'first' => 'System', + 'last' => 'Accounts', + 'complimentary' => 'Y', 'bill_location' => $cust_location, 'ship_location' => $cust_location, }, diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm index 263be80..35a1e19 100644 --- a/FS/FS/Upgrade.pm +++ b/FS/FS/Upgrade.pm @@ -312,6 +312,9 @@ sub upgrade_data { #payby conditions to new ones 'part_event_condition' => [], + #payby actions to new ones + 'part_event' => [], + #cust_main (remove paycvv from history, locations, cust_payby, etc) 'cust_main' => [], diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 068d0d1..8d69661 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -6,6 +6,7 @@ use base qw( FS::cust_bill::Search FS::Template_Mixin use strict; use vars qw( $DEBUG $me ); # but NOT $conf +use Carp; use Fcntl qw(:flock); #for spool_csv use Cwd; use List::Util qw(min max sum); @@ -26,11 +27,9 @@ use FS::cust_pay; use FS::cust_pkg; use FS::cust_credit_bill; use FS::pay_batch; -use FS::cust_bill_event; use FS::cust_event; use FS::part_pkg; use FS::cust_bill_pay; -use FS::part_bill_event; use FS::payby; use FS::bill_batch; use FS::cust_bill_batch; @@ -285,7 +284,6 @@ sub delete { my $dbh = dbh; foreach my $table (qw( - cust_bill_event cust_event cust_credit_bill cust_bill_pay @@ -565,32 +563,6 @@ sub open_cust_bill_pkg { @open; } -=item cust_bill_event - -Returns the completed invoice events (deprecated, old-style events - see L<FS::cust_bill_event>) for this invoice. - -=cut - -sub cust_bill_event { - my $self = shift; - qsearch( 'cust_bill_event', { 'invnum' => $self->invnum } ); -} - -=item num_cust_bill_event - -Returns the number of completed invoice events (deprecated, old-style events - see L<FS::cust_bill_event>) for this invoice. - -=cut - -sub num_cust_bill_event { - my $self = shift; - my $sql = - "SELECT COUNT(*) FROM cust_bill_event WHERE invnum = ?"; - my $sth = dbh->prepare($sql) or die dbh->errstr. " preparing $sql"; - $sth->execute($self->invnum) or die $sth->errstr. " executing $sql"; - $sth->fetchrow_arrayref->[0]; -} - =item cust_event Returns the new-style customer billing events (see L<FS::cust_event>) for this invoice. @@ -1982,24 +1954,8 @@ sub print_csv { } -=item comp - -Pays this invoice with a compliemntary payment. If there is an error, -returns the error, otherwise returns false. - -=cut - sub comp { - my $self = shift; - my $cust_pay = new FS::cust_pay ( { - 'invnum' => $self->invnum, - 'paid' => $self->owed, - '_date' => '', - 'payby' => 'COMP', - 'payinfo' => $self->cust_main->payinfo, - 'paybatch' => '', - } ); - $cust_pay->insert; + croak 'cust_bill->comp is deprecated (COMP payments are deprecated)'; } =item realtime_card diff --git a/FS/FS/cust_bill/Search.pm b/FS/FS/cust_bill/Search.pm index 1fc818d..2a67529 100644 --- a/FS/FS/cust_bill/Search.pm +++ b/FS/FS/cust_bill/Search.pm @@ -128,10 +128,6 @@ Return only invoices belonging to that customer. Limit to that customer class (single value or arrayref). -=item payby - -Limit to customers with that payment method (single value or arrayref). - =item refnum Limit to customers with that advertising source. @@ -194,14 +190,6 @@ sub search_sql_where { } - #payby - if ( $param->{payby} ) { - my $payby = $param->{payby}; - $payby = [ $payby ] unless ref $payby; - my $payby_in = join(',', map {dbh->quote($_)} @$payby); - push @search, "cust_main.payby IN($payby_in)" if length($payby_in); - } - #_date if ( $param->{_date} ) { my($beginning, $ending) = @{$param->{_date}}; diff --git a/FS/FS/cust_bill_event.pm b/FS/FS/cust_bill_event.pm deleted file mode 100644 index adaa13e..0000000 --- a/FS/FS/cust_bill_event.pm +++ /dev/null @@ -1,378 +0,0 @@ -package FS::cust_bill_event; - -use strict; -use vars qw( @ISA $DEBUG ); -use FS::Record qw( qsearch qsearchs ); -use FS::cust_main_Mixin; -use FS::cust_bill; -use FS::part_bill_event; - -@ISA = qw(FS::cust_main_Mixin FS::Record); - -$DEBUG = 0; - -=head1 NAME - -FS::cust_bill_event - Object methods for cust_bill_event records - -=head1 SYNOPSIS - - use FS::cust_bill_event; - - $record = new FS::cust_bill_event \%hash; - $record = new FS::cust_bill_event { 'column' => 'value' }; - - $error = $record->insert; - - $error = $new_record->replace($old_record); - - $error = $record->delete; - - $error = $record->check; - -=head1 DESCRIPTION - -An FS::cust_bill_event object represents an complete invoice event. -FS::cust_bill_event inherits from FS::Record. The following fields are -currently supported: - -=over 4 - -=item eventnum - -Primary key - -=item invnum - -Invoice (see L<FS::cust_bill>) - -=item eventpart - -Event definition (see L<FS::part_bill_event>) - -=item _date - -Specified as a UNIX timestamp; see L<perlfunc/"time">. Also see -L<Time::Local> and L<Date::Parse> for conversion functions. - -=item status - -Event status: B<done> or B<failed> - -=item statustext - -Additional status detail (i.e. error message) - -=back - -=head1 METHODS - -=over 4 - -=item new HASHREF - -Creates a new completed invoice event. To add the compelted invoice event to -the database, see L<"insert">. - -Note that this stores the hash reference, not a distinct copy of the hash it -points to. You can ask the object for a copy with the I<hash> method. - -=cut - -# the new method can be inherited from FS::Record, if a table method is defined - -sub table { 'cust_bill_event'; } - -sub cust_linked { $_[0]->cust_main_custnum || $_[0]->custnum } -sub cust_unlinked_msg { - my $self = shift; - "WARNING: can't find cust_main.custnum ". $self->custnum. - ' (cust_bill.invnum '. $self->invnum. ')'; -} - -=item insert - -Adds this record to the database. If there is an error, returns the error, -otherwise returns false. - -=cut - -# the insert method can be inherited from FS::Record - -=item delete - -Delete this record from the database. - -=cut - -# the delete method can be inherited from FS::Record - -=item replace OLD_RECORD - -Replaces the OLD_RECORD with this one in the database. If there is an error, -returns the error, otherwise returns false. - -=cut - -# the replace method can be inherited from FS::Record - -=item check - -Checks all fields to make sure this is a valid completed invoice event. If -there is an error, returns the error, otherwise returns false. Called by the -insert and replace methods. - -=cut - -# the check method should currently be supplied - FS::Record contains some -# data checking routines - -sub check { - my $self = shift; - - my $error = $self->ut_numbern('eventnum') - || $self->ut_number('invnum') - || $self->ut_number('eventpart') - || $self->ut_number('_date') - || $self->ut_enum('status', [qw( done failed )]) - || $self->ut_anything('statustext') - ; - - return "Unknown eventpart ". $self->eventpart - unless my $part_bill_event = - qsearchs( 'part_bill_event' ,{ 'eventpart' => $self->eventpart } ); - - return "Unknown invnum ". $self->invnum - unless qsearchs( 'cust_bill' ,{ 'invnum' => $self->invnum } ); - - $self->SUPER::check; -} - -=item part_bill_event - -Returns the invoice event definition (see L<FS::part_bill_event>) for this -completed invoice event. - -=cut - -sub part_bill_event { - my $self = shift; - qsearchs( 'part_bill_event', { 'eventpart' => $self->eventpart } ); -} - -=item cust_bill - -Returns the invoice (see L<FS::cust_bill>) for this completed invoice event. - -=cut - -sub cust_bill { - my $self = shift; - qsearchs( 'cust_bill', { 'invnum' => $self->invnum } ); -} - -=item retry - -Changes the status of this event from B<done> to B<failed>, allowing it to be -retried. - -=cut - -sub retry { - my $self = shift; - return '' unless $self->status eq 'done'; - my $old = ref($self)->new( { $self->hash } ); - $self->status('failed'); - $self->replace($old); -} - -=item retryable - -Changes the statustext of this event to B<retriable>, rendering it -retriable (should retry be called). - -=cut - -sub retriable { - my $self = shift; - return '' unless $self->status eq 'done'; - my $old = ref($self)->new( { $self->hash } ); - $self->statustext('retriable'); - $self->replace($old); -} - -=item search_sql_where HASHREF - -Class method which returns an SQL WHERE fragment to search for parameters -specified in HASHREF. Valid parameters are - -=over 4 - -=item agentnum - -=item beginning - -An epoch date setting a lower bound for _date values - -=item ending - -An epoch date setting a upper bound for _date values - -=item failed - -Limits the search to failed events if true - -=item payby - -Requires that the search be JOIN'd to part_bill_event # Bug? - -=item invnum - -=item currentuser - -Specifies the user for agent virtualization - -=back - -=cut - -sub search_sql_where { - my ($class, $params) = @_; - my @search = (); - - push @search, "agentnum = ". $params->{agentnum} if $params->{agentnum}; - - push @search, "cust_bill_event._date >= ". $params->{beginning} - if $params->{beginning}; - push @search, "cust_bill_event._date <= ". $params->{ending} - if $params->{ending}; - - push @search, "statustext != ''", - "statustext IS NOT NULL", - "statustext != 'N/A'" - if $params->{failed}; - - push @search, "part_bill_event.payby = '". $params->{payby}. "'" - if $params->{payby}; - - push @search, "cust_bill_event.invnum = '". $params->{invnum}. "'" - if $params->{invnum}; - - my $currentuser = $params->{currentuser} || $params->{CurrentUser}; - if ($currentuser) { - my $access_user = qsearchs('access_user', { username => $currentuser }); - if ($access_user) { - push @search, $access_user->agentnums_sql; - }else{ - push @search, "1=0"; - } - }else{ - push @search, $FS::CurrentUser::CurrentUser->agentnums_sql; - } - - join(' AND ', @search ); - -} - -=back - -=head1 SUBROUTINES - -=over 4 - -=item reprint - -=cut - -sub process_reprint { - process_re_X('print', @_); -} - -=item reemail - -=cut - -sub process_reemail { - process_re_X('email', @_); -} - -=item refax - -=cut - -sub process_refax { - process_re_X('fax', @_); -} - -use Data::Dumper; -sub process_re_X { - my( $method, $job ) = ( shift, shift ); - - my $param = shift; - warn Dumper($param) if $DEBUG; - - re_X( - $method, - $param, - $job, - ); - -} - -sub re_X { - my($method, $param, $job) = @_; - - my $where = FS::cust_bill_event->search_sql_where($param); - $where = " WHERE plan LIKE 'send%'". ( $where ? " AND $where" : "" ); - - my $from = 'LEFT JOIN part_bill_event USING ( eventpart )'. - 'LEFT JOIN cust_bill USING ( invnum )'. - 'LEFT JOIN cust_main USING ( custnum )'; - - my @cust_bill_event = qsearch( 'cust_bill_event', {}, '', $where, '', $from ); - - my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo - foreach my $cust_bill_event ( @cust_bill_event ) { - - $cust_bill_event->cust_bill->$method( - $cust_bill_event->part_bill_event->templatename - ); - - if ( $job ) { #progressbar foo - $num++; - if ( time - $min_sec > $last ) { - my $error = $job->update_statustext( - int( 100 * $num / scalar(@cust_bill_event) ) - ); - die $error if $error; - $last = time; - } - } - - } - - #this doesn't work, but it would be nice - #if ( $job ) { #progressbar foo - # my $error = $job->update_statustext( - # scalar(@cust_bill_event). " invoices re-${method}ed" - # ); - # die $error if $error; - #} - -} - -=back - -=head1 BUGS - -Far too early in the morning. - -=head1 SEE ALSO - -L<FS::part_bill_event>, L<FS::cust_bill>, L<FS::Record>, schema.html from the -base documentation. - -=cut - -1; - diff --git a/FS/FS/cust_event.pm b/FS/FS/cust_event.pm index d7a35a7..f299f93 100644 --- a/FS/FS/cust_event.pm +++ b/FS/FS/cust_event.pm @@ -337,10 +337,6 @@ specified in HASHREF. Valid parameters are =item ending -=item payby - -=item - =back =cut diff --git a/FS/FS/cust_main/API.pm b/FS/FS/cust_main/API.pm index 158b5cf..2d6da9e 100644 --- a/FS/FS/cust_main/API.pm +++ b/FS/FS/cust_main/API.pm @@ -21,8 +21,7 @@ use vars 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 ); @@ -106,14 +105,12 @@ sub API_insert { #same for refnum like signup_server-default_refnum? my $cust_main = new FS::cust_main ( { # $class->new( { - 'payby' => 'BILL', 'tagnum' => [ FS::part_tag->default_tags ], map { $_ => $opt{$_} } qw( agentnum salesnum refnum agent_custid referral_custnum last first company daytime night fax mobile - payby payinfo paydate paycvv payname ), } ); @@ -176,7 +173,6 @@ sub API_update { agentnum salesnum refnum agent_custid referral_custnum last first company daytime night fax mobile - payby payinfo paydate paycvv payname ), my @invoicing_list; diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 9e2082f..b3d4e70 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -390,7 +390,7 @@ terms or the default terms are used. sub bill { my( $self, %options ) = @_; - return '' if $self->payby eq 'COMP'; + return '' if $self->complimentary eq 'Y'; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; my $log = FS::Log->new('FS::cust_main::Billing::bill'); diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm index 20698fb..1f6a9e9 100644 --- a/FS/FS/cust_main/Billing_Realtime.pm +++ b/FS/FS/cust_main/Billing_Realtime.pm @@ -45,6 +45,36 @@ These methods are available on FS::cust_main objects. =over 4 +=item realtime_cust_payby + +=cut + +sub realtime_cust_payby { + my( $self, %options ) = @_; + + local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; + + $options{amount} = $self->balance unless exists( $options{amount} ); + + my @cust_payby = qsearch({ + 'table' => 'cust_payby', + 'hashref' => { 'custnum' => $self->custnum, }, + 'extra_sql' => " AND payby IN ( 'CARD', 'CHEK' ) ", + 'order_by' => 'ORDER BY weight ASC', + }); + + my $error; + foreach my $cust_payby (@cust_payby) { + $error = $cust_payby->realtime_bop( %options, ); + last unless $error; + } + + #XXX what about the earlier errors? + + $error; + +} + =item realtime_collect [ OPTION => VALUE ... ] Attempt to collect the customer's current balance with a realtime credit diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 139d2ff..e8f9aee 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -978,7 +978,6 @@ sub _upgrade_data { #class method $cust_pay->set('otaker', 'legacy'); } - delete $FS::payby::hash{'COMP'}->{cust_pay}; #quelle kludge my $error = $cust_pay->replace; if ( $error ) { @@ -987,8 +986,6 @@ sub _upgrade_data { #class method next; } - $FS::payby::hash{'COMP'}->{cust_pay} = ''; #restore it - $count++; if ( $DEBUG > 1 && $lastprog + 30 < time ) { warn "$me $count/$total (".sprintf('%.2f',100*$count/$total). '%)'."\n"; @@ -1042,9 +1039,7 @@ sub _upgrade_data { #class method # otaker->usernum upgrade ### - delete $FS::payby::hash{'COMP'}->{cust_pay}; #quelle kludge $class->_upgrade_otaker(%opt); - $FS::payby::hash{'COMP'}->{cust_pay} = ''; #restore it # if we do this anywhere else, it should become an FS::Upgrade method my $num_to_upgrade = $class->count('paybatch is not null'); diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm index d4d40b5..a4b4957 100644 --- a/FS/FS/cust_pay_batch.pm +++ b/FS/FS/cust_pay_batch.pm @@ -49,7 +49,7 @@ following fields are currently supported: =item batchnum - indentifies group in batch -=item payby - CARD/CHEK/LECB/BILL/COMP +=item payby - CARD/CHEK =item payinfo @@ -154,7 +154,7 @@ sub check { if ( $self->exp eq '' ) { return "Expiration date required" - unless $self->payby =~ /^(CHEK|DCHK|LECB|WEST)$/; + unless $self->payby =~ /^(CHEK|DCHK|WEST)$/; $self->exp(''); } else { if ( $self->exp =~ /^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})$/ ) { @@ -246,39 +246,6 @@ sub retriable { confess "deprecated method cust_pay_batch->retriable called; try removing ". "the once condition and adding an every condition?"; - my $self = shift; - - local $SIG{HUP} = 'IGNORE'; #Hmm - 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 $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } ) - or return "event $self->eventnum references nonexistant invoice $self->invnum"; - - warn "cust_pay_batch->retriable working with self of " . $self->paybatchnum . " and invnum of " . $self->invnum; - my @cust_bill_event = - sort { $a->part_bill_event->seconds <=> $b->part_bill_event->seconds } - grep { - $_->part_bill_event->eventcode =~ /\$cust_bill->batch_card/ - && $_->status eq 'done' - && ! $_->statustext - } - $cust_bill->cust_bill_event; - # complain loudly if scalar(@cust_bill_event) > 1 ? - my $error = $cust_bill_event[0]->retriable; - if ($error ) { - # gah, even with transactions. - $dbh->commit if $oldAutoCommit; #well. - return "error marking invoice event retriable: $error"; - } - ''; } =item approve OPTIONS diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm index a65a171..b1a7ddb 100644 --- a/FS/FS/cust_payby.pm +++ b/FS/FS/cust_payby.pm @@ -427,12 +427,16 @@ sub check { } - if ( $self->paydate eq '' || $self->paydate eq '-' ) { - return "Expiration date required" - # shouldn't payinfo_check do this? - unless $self->payby =~ /^(CHEK|DCHK)$/; + if ( $self->payby =~ /^(CHEK|DCHK)$/ ) { + $self->paydate(''); - } else { + + } elsif ( $self->payby =~ /^(CARD|DCRD)$/ ) { + + # shouldn't payinfo_check do this? + return "Expiration date required" + if $self->paydate eq '' || $self->paydate eq '-'; + my( $m, $y ); if ( $self->paydate =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ ) { ( $m, $y ) = ( $1, length($2) == 4 ? $2 : "20$2" ); @@ -451,6 +455,7 @@ sub check { #&& !$ignore_expired_card && ( $y<$nowy || ( $y==$nowy && $1<$nowm ) ); + } if ( $self->payname eq '' && $self->payby !~ /^(CHEK|DCHK)$/ && @@ -560,7 +565,7 @@ Returns the field names used in the web interface (including some pseudo-fields) sub cgi_cust_payby_fields { #my $class = shift; [qw( payby payinfo paydate_month paydate_year paycvv payname weight - payinfo1 payinfo2 payinfo3 paytype paystate )]; + payinfo1 payinfo2 payinfo3 paytype paystate payname_CHEK )]; } =item cgi_hash_callback HASHREF @@ -582,7 +587,7 @@ sub cgi_hash_callback { if ( $hashref->{payby} =~ /^(CHEK|DCHK)$/ ) { - unless ( grep $hashref->{$_}, qw( payinfo1 payinfo2 payinfo3 payname ) ) { + unless ( grep $hashref->{$_}, qw(payinfo1 payinfo2 payinfo3 payname_CHEK)) { %$hashref = (); return; } @@ -592,7 +597,7 @@ sub cgi_hash_callback { if $conf->config('echeck-country') eq 'CA'; $hashref->{payinfo} .= $hashref->{'payinfo2'}; - $hashref->{payname} .= $hashref->{'payname_CHEK'}; + $hashref->{payname} = $hashref->{'payname_CHEK'}; } elsif ( $hashref->{payby} =~ /^(CARD|DCRD)$/ ) { diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm deleted file mode 100644 index 4e7aa52..0000000 --- a/FS/FS/part_bill_event.pm +++ /dev/null @@ -1,368 +0,0 @@ -package FS::part_bill_event; - -use strict; -use vars qw( @ISA $DEBUG @EXPORT_OK ); -use Carp qw(cluck confess); -use FS::Record qw( dbh qsearch qsearchs ); -use FS::Conf; -use FS::cust_main; -use FS::cust_bill; - -@ISA = qw( FS::Record ); -@EXPORT_OK = qw( due_events ); -$DEBUG = 0; - -=head1 NAME - -FS::part_bill_event - Object methods for part_bill_event records - -=head1 SYNOPSIS - - use FS::part_bill_event; - - $record = new FS::part_bill_event \%hash; - $record = new FS::part_bill_event { 'column' => 'value' }; - - $error = $record->insert; - - $error = $new_record->replace($old_record); - - $error = $record->delete; - - $error = $record->check; - - $error = $record->do_event( $direct_object ); - - @events = due_events ( { 'record' => $event_triggering_record, - 'payby' => $payby, - 'event_time => $_date, - 'extra_sql => $extra } ); - -=head1 DESCRIPTION - -An FS::part_bill_event object represents a deprecated, old-style invoice event -definition - a callback which is triggered when an invoice is a certain amount -of time overdue. FS::part_bill_event inherits from FS::Record. The following -fields are currently supported: - -=over 4 - -=item eventpart - primary key - -=item payby - CARD, DCRD, CHEK, DCHK, LECB, BILL, or COMP - -=item event - event name - -=item eventcode - event action - -=item seconds - how long after the invoice date events of this type are triggered - -=item weight - ordering for events with identical seconds - -=item plan - eventcode plan - -=item plandata - additional plan data - -=item reason - an associated reason for this event to fire - -=item disabled - Disabled flag, empty or `Y' - -=back - -=head1 NOTE - -Old-style invoice events are only useful for legacy migrations - if you are -looking for current events see L<FS::part_event>. - -=head1 METHODS - -=over 4 - -=item new HASHREF - -Creates a new invoice event definition. To add the invoice event definition to -the database, see L<"insert">. - -Note that this stores the hash reference, not a distinct copy of the hash it -points to. You can ask the object for a copy with the I<hash> method. - -=cut - -# the new method can be inherited from FS::Record, if a table method is defined - -sub table { 'part_bill_event'; } - -=item insert - -Adds this record to the database. If there is an error, returns the error, -otherwise returns false. - -=cut - -# the insert method can be inherited from FS::Record - -=item delete - -Delete this record from the database. - -=cut - -# the delete method can be inherited from FS::Record - -=item replace OLD_RECORD - -Replaces the OLD_RECORD with this one in the database. If there is an error, -returns the error, otherwise returns false. - -=cut - -# the replace method can be inherited from FS::Record - -=item check - -Checks all fields to make sure this is a valid invoice event definition. If -there is an error, returns the error, otherwise returns false. Called by the -insert and replace methods. - -=cut - -# the check method should currently be supplied - FS::Record contains some -# data checking routines - -sub check { - my $self = shift; - - $self->weight(0) unless $self->weight; - - my $conf = new FS::Conf; - if ( $conf->exists('safe-part_bill_event') ) { - my $error = $self->ut_anything('eventcode'); - return $error if $error; - - my $c = $self->eventcode; - - #yay, these regexen will go away with the event refactor - - $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/ - - or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/ - - or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/ - -# or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/ - or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/ - - or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/ - - or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/ - - or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/ - - or do { - #log - return "illegal eventcode: $c"; - }; - - } - - my $error = $self->ut_numbern('eventpart') - || $self->ut_enum('payby', [qw( CARD DCLN DCRD CHEK DCHK LECB BILL COMP )] ) - || $self->ut_text('event') - || $self->ut_anything('eventcode') - || $self->ut_number('seconds') - || $self->ut_enum('disabled', [ '', 'Y' ] ) - || $self->ut_number('weight') - || $self->ut_textn('plan') - || $self->ut_anything('plandata') - || $self->ut_numbern('reason') - ; - #|| $self->ut_snumber('seconds') - return $error if $error; - - #quelle kludge - if ( $self->plandata =~ /^(agent_)?templatename\s+(.*)$/m ) { - my $name= $2; - - foreach my $file (qw( template - latex latexnotes latexreturnaddress latexfooter - latexsmallfooter - html htmlnotes htmlreturnaddress htmlfooter - )) - { - unless ( $conf->exists("invoice_${file}_$name") ) { - $conf->set( - "invoice_${file}_$name" => - join("\n", $conf->config("invoice_$file") ) - ); - } - } - } - - if ($self->reason){ - my $reasonr = qsearchs('reason', {'reasonnum' => $self->reason}); - return "Unknown reason" unless $reasonr; - } - - $self->SUPER::check; -} - -=item templatename - -Returns the alternate invoice template name, if any, or false if there is -no alternate template for this invoice event. - -=cut - -sub templatename { - my $self = shift; - if ( $self->plan =~ /^send_(alternate|agent)$/ - && $self->plandata =~ /^(agent_)?templatename (.*)$/m - ) - { - $2; - } else { - ''; - } -} - -=item due_events - -Returns the list of events due, if any, or false if there is none. -Requires record and payby, but event_time and extra_sql are optional. - -=cut - -sub due_events { - my ($record, $payby, $event_time, $extra_sql) = @_; - - #cluck "DEPRECATED: FS::part_bill_event::due_events called on $record"; - confess "DEPRECATED: FS::part_bill_event::due_events called on $record"; - - my $interval = 0; - if ($record->_date){ - $event_time = time unless $event_time; - $interval = $event_time - $record->_date; - } - sort { $a->seconds <=> $b->seconds - || $a->weight <=> $b->weight - || $a->eventpart <=> $b->eventpart } - grep { ref($record) ne 'FS::cust_bill' || $_->eventcode !~ /honor_dundate/ - || $event_time > $record->cust_main->dundate - } - grep { $_->seconds <= ( $interval ) - && ! qsearch( 'cust_bill_event', { - 'invnum' => $record->get($record->dbdef_table->primary_key), - 'eventpart' => $_->eventpart, - 'status' => 'done', - } ) - } - qsearch( { - 'table' => 'part_bill_event', - 'hashref' => { 'payby' => $payby, - 'disabled' => '', }, - 'extra_sql' => $extra_sql, - } ); - - -} - -=item do_event - -Performs the event and returns any errors that occur. -Requires a record on which to perform the event. -Should only be performed inside a transaction. - -=cut - -sub do_event { - my ($self, $object, %options) = @_; - - #cluck "DEPRECATED: FS::part_bill_event::do_event called on $self"; - confess "DEPRECATED: FS::part_bill_event::do_event called on $self"; - - warn " calling event (". $self->eventcode. ") for " . $object->table . " " , - $object->get($object->dbdef_table->primary_key) . "\n" if $DEBUG > 1; - my $oldAutoCommit = $FS::UID::AutoCommit; - local $FS::UID::AutoCommit = 0; - - # for "callback" -- heh - my $cust_main = $object->cust_main; - my $cust_bill; - if ($object->table eq 'cust_bill'){ - $cust_bill = $object; - } - my $cust_pay_batch; - if ($object->table eq 'cust_pay_batch'){ - $cust_pay_batch = $object; - } - - my $error; - { - local $SIG{__DIE__}; # don't want Mason __DIE__ handler active - $error = eval $self->eventcode; - } - - my $status = ''; - my $statustext = ''; - if ( $@ ) { - $status = 'failed'; - $statustext = $@; - } elsif ( $error ) { - $status = 'done'; - $statustext = $error; - } else { - $status = 'done'; - } - - #add cust_bill_event - my $cust_bill_event = new FS::cust_bill_event { -# 'invnum' => $object->get($object->dbdef_table->primary_key), - 'invnum' => $object->invnum, - 'eventpart' => $self->eventpart, - '_date' => time, - 'status' => $status, - 'statustext' => $statustext, - }; - $error = $cust_bill_event->insert; - if ( $error ) { - my $e = 'WARNING: Event run but database not updated - '. - 'error inserting cust_bill_event, invnum #'. $object->invnum . - ', eventpart '. $self->eventpart.": $error"; - warn $e; - return $e; - } - ''; -} - -=item reasontext - -Returns the text of any reason associated with this event. - -=cut - -sub reasontext { - my $self = shift; - my $r = qsearchs('reason', { 'reasonnum' => $self->reason }); - if ($r){ - $r->reason; - }else{ - ''; - } -} - -=back - -=head1 BUGS - -The whole "eventcode" idea is bunk. This should be refactored with subclasses -like part_pkg/ and part_export/ - -=head1 SEE ALSO - -L<FS::cust_bill>, L<FS::cust_bill_event>, L<FS::Record>, schema.html from the -base documentation. - -=cut - -1; - diff --git a/FS/FS/part_event.pm b/FS/FS/part_event.pm index e7acf5a..d15f35b 100644 --- a/FS/FS/part_event.pm +++ b/FS/FS/part_event.pm @@ -604,6 +604,22 @@ sub process_initialize { $part_event->initialize; } +sub _upgrade_data { #class method + my ($class, %opts) = @_; + + foreach my $part_event ( + qsearch('part_event', { 'action' => 'cust_bill_realtime_card' }), + qsearch('part_event', { 'action' => 'cust_bill_realtime_check' }), + ) { + + $part_event->action('realtime_auto'); + my $error = $part_event->replace; + die $error if $error; + + } + +} + =back =head1 SEE ALSO diff --git a/FS/FS/part_event/Action/realtime_auto.pm b/FS/FS/part_event/Action/realtime_auto.pm new file mode 100644 index 0000000..3902319 --- /dev/null +++ b/FS/FS/part_event/Action/realtime_auto.pm @@ -0,0 +1,41 @@ +package FS::part_event::Action::realtime_auto; + +use strict; +use base qw( FS::part_event::Action ); + +sub description { + #'Run card with a <a href="http://420.am/business-onlinepayment/">Business::OnlinePayment</a> realtime gateway'; + 'Run card or check with a Business::OnlinePayment realtime gateway'; +} + +sub eventtable_hashref { + { 'cust_bill' => 1, + 'cust_main' => 1, + }; +} + +sub default_weight { 30; } + +sub do_action { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + my %opt = ('cc_surcharge_from_event' => 1); + + my $amount; + my $balance = $cust_main->balance; + if ( ref($object) eq 'FS::cust_main' ) { + $amount = $balance; + } elsif ( ref($object) eq 'FS::cust_bill' ) { + $amount = ( $balance < $object->owed ) ? $balance : $object->owed; + $opt{'invnum'} = $object->invnum; + } else { + die 'guru meditation #5454.au'; + } + + $cust_main->realtime_cust_payby( 'amount' => $amount, %opt, ); + +} + +1; diff --git a/FS/FS/pay_batch/RBC.pm b/FS/FS/pay_batch/RBC.pm index a5c4683..4b11fdb 100644 --- a/FS/FS/pay_batch/RBC.pm +++ b/FS/FS/pay_batch/RBC.pm @@ -108,7 +108,7 @@ $name = 'RBC'; sprintf("%3s",$trans_code). sprintf("%10s",$client_num). ' '. - sprintf("%-19s", $cust_pay_batch->cust_main->custnum). + sprintf("%-19s", $cust_pay_batch->paybatchnum). '00'. sprintf("%04s", $bankno). sprintf("%05s", $branch). diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index ec3bb12..0047f9d 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -2055,9 +2055,6 @@ sub generate_liability_report { join(';', map { "$_=". uri_escape($t->$_) } @params); my $itemdesc_loc = - # " payby != 'COMP' ". # breaks the entire report under 4.x - # # and unnecessary since COMP accounts don't - # # get taxes calculated in the first place " ( itemdesc = ? OR ? = '' AND itemdesc IS NULL ) ". "AND ". FS::tax_rate_location->location_sql( map { $_ => $t->$_ } @taxparams diff --git a/FS/MANIFEST b/FS/MANIFEST index b7d347b..0542dfd 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -86,7 +86,6 @@ FS/cust_main_Mixin.pm FS/cust_main_county.pm FS/cust_main_invoice.pm FS/cust_pay.pm -FS/cust_bill_event.pm FS/cust_bill_pay.pm FS/cust_pay_batch.pm FS/cust_pay_refund.pm @@ -110,7 +109,6 @@ FS/h_svc_domain.pm FS/h_svc_external.pm FS/h_svc_forward.pm FS/h_svc_www.pm -FS/part_bill_event.pm FS/payinfo_Mixin.pm FS/export_svc.pm FS/export_device.pm @@ -246,7 +244,6 @@ t/UID.t t/Msgcat.t t/SearchCache.t t/cust_bill.t -t/cust_bill_event.t t/cust_bill_pay.t t/cust_bill_pkg.t t/cust_bill_pkg_detail.t @@ -280,7 +277,6 @@ t/cust_tax_exempt.t t/cust_tax_exempt_pkg.t t/domain_record.t t/nas.t -t/part_bill_event.t t/export_svc.t t/export_device.t t/part_export.t diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index f14e2b3..af48ec0 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -12,6 +12,11 @@ getopts("p:a:d:vl:sy:nmrkg:o", \%opt); my $user = shift or die &usage; adminsuidsetup $user; + +die "The -p option has been removed in version 4 -- customers no longer have ". + "a single, specific payment type\n" + if $opt{'p'}; + my $log = FS::Log->new('daily'); $log->info('start'); @@ -108,7 +113,7 @@ sub untaint_argv { } sub usage { - die "Usage:\n\n freeside-daily [ -d 'date' ] [ -y days ] [ -p 'payby' ] [ -a agentnum,agentnum,... ] [ -s ] [ -v ] [ -l level ] [ -m ] [ -k ] user [ custnum custnum ... ]\n"; + die "Usage:\n\n freeside-daily [ -d 'date' ] [ -y days ] [ -a agentnum,agentnum,... ] [ -s ] [ -v ] [ -l level ] [ -m ] [ -k ] user [ custnum custnum ... ]\n"; } ### @@ -121,7 +126,7 @@ freeside-daily - Run daily billing and invoice collection events. =head1 SYNOPSIS - freeside-daily [ -d 'date' ] [ -y days ] [ -p 'payby' ] [ -a agentnum,agentnum,... ] [ -s ] [ -o ] [ -v ] [ -l level ] [ -m ] [ -r ] [ -k ] user [ custnum custnum ... ] + freeside-daily [ -d 'date' ] [ -y days ] [ -a agentnum,agentnum,... ] [ -s ] [ -o ] [ -v ] [ -l level ] [ -m ] [ -r ] [ -k ] user [ custnum custnum ... ] =head1 DESCRIPTION @@ -143,7 +148,7 @@ the bill and collect methods of a cust_main object. See L<FS::cust_main>. with today's date, irregardless of the pretend date used to pre-generate the invoices. - -p: Only process customers with the specified payby (CARD, DCRD, CHEK, DCHK, BILL, COMP, LECB) + -p: Deprecated, will produce a fatal error (formerly was: Only process customers with the specified payby (CARD, DCRD, CHEK, DCHK, BILL, COMP, LECB)) -a: Only process customers with the specified agentnum. Multiple agentnums can be specified, separated with commas. diff --git a/FS/bin/freeside-monthly b/FS/bin/freeside-monthly index 431fbd8..7be3776 100755 --- a/FS/bin/freeside-monthly +++ b/FS/bin/freeside-monthly @@ -12,6 +12,10 @@ getopts("p:a:d:vsy:m", \%opt); my $user = shift or die &usage; adminsuidsetup $user; +die "The -p option has been removed in version 4 -- customers no longer have ". + "a single, specific payment type" + if $opt{'p'}; + use FS::Cron::bill qw(bill); bill(%opt, 'check_freq'=>'1m' ); @@ -45,7 +49,7 @@ freeside-monthly - Run monthly billing and invoice collection events. =head1 SYNOPSIS - freeside-monthly [ -d 'date' ] [ -y days ] [ -p 'payby' ] [ -a agentnum ] [ -s ] [ -v ] user [ custnum custnum ... ] + freeside-monthly [ -d 'date' ] [ -y days ] [ -a agentnum ] [ -s ] [ -v ] user [ custnum custnum ... ] =head1 DESCRIPTION @@ -64,7 +68,7 @@ the bill and collect methods of a cust_main object. See L<FS::cust_main>. "pretend date" 15 days from whatever was specified by the -d switch (or now, if no -d switch was given). - -p: Only process customers with the specified payby (CARD, DCRD, CHEK, DCHK, BILL, COMP, LECB) + -p: Deprecated, will produce a fatal error (formerly was: Only process customers with the specified payby (CARD, DCRD, CHEK, DCHK, BILL, COMP, LECB)) -a: Only process customers with the specified agentnum diff --git a/FS/bin/freeside-vitelity-cdrimport b/FS/bin/freeside-vitelity-cdrimport new file mode 100755 index 0000000..83bbdd9 --- /dev/null +++ b/FS/bin/freeside-vitelity-cdrimport @@ -0,0 +1,132 @@ +#!/usr/bin/perl + +=pod + +freeside-vitelity-cdrimport [ -v ] [ -k ] + -s date -e date + username + [ exportnum ] + +Download CDRs using the Vitelity API. + +-v: Be verbose. + +-k: Keep the .csv file for debugging purposes, instead of deleting it. + +-s date: Import only records on or after 'date' Now required as the Vitelity +API has changed. + +-e date: Import only records before 'date'. Now required as the Vitelity API +has changed. + +username: a Freeside user + +exportnum: Run only for that export. If not specified, this will run for +all Vitelity exports. + +=cut + +use strict; +use FS::UID qw(adminsuidsetup dbh); +use FS::Record qw(qsearchs qsearch); +use FS::cdr; +use FS::part_export; +use Getopt::Std; +use File::Temp; +use Date::Format 'time2str'; +use Date::Parse 'str2time'; + +my %opt; +getopts('vks:e:', \%opt); + +my $user = shift or die &usage; +my $exportnum = shift; +my $dbh = adminsuidsetup $user; + +my $start = $opt{'s'} ? str2time($opt{'s'}) : die &usage('-s is now required'); +my $end = $opt{'e'} ? str2time($opt{'e'}) : die &usage('-e is now required'); + +local $FS::UID::AutoCommit = 0; + +my @part_exports; +if ( $exportnum ) { + @part_exports = ( qsearchs('part_export', { 'exportnum' => $exportnum }) ) + or die "exportnum $exportnum not found\n"; +} +else { + @part_exports = qsearch('part_export', { 'exporttype' => 'vitelity' }) + or die "no Vitelity exports found\n"; +} + +foreach my $export (@part_exports) { + my $exportnum = $export->exportnum; + print "Processing exportnum $exportnum.\n" if $opt{'v'}; + $export->isa('FS::part_export::vitelity') + or die "exportnum $exportnum is not a Vitelity export\n"; + + my $dir = $FS::UID::cache_dir . "/cache.". $FS::UID::datasrc; + my $temp = new File::Temp ( TEMPLATE => 'download.XXXXXXXX', + SUFFIX => '.csv', + DIR => $dir, + UNLINK => !$opt{'k'} ) + or die "can't open temporary file to store download: $!\n"; + print "Downloading to ".$temp->filename."\n" if $opt{'v'}; + + print "Sending API request..." if $opt{'v'}; + + my $s = time2str('%m-%d-%Y', $start); + my $e = time2str('%m-%d-%Y', $end); + + my @records = eval { $export->vitelity_command('getcdr', + 'startdate' => $s, + 'enddate' => $e, + ); + }; + if ( $@ ) { + print "download error: $@\n"; + exit(-1); + } + + print "received ".scalar(@records)." records\n" if $opt{'v'}; + if ( !@records ) { + print "No records to process.\n" if $opt{'v'}; + exit(1); + } + + print $temp "Date,Source,Destination,Seconds,CallerID,Disposition,Cost\n"; + + while (my $rec = shift @records) { + print $temp $rec, "\n"; + } + close $temp; + + my $format = 'vitelity'; + my $batchname = "vitelity-$exportnum-".time2str('%Y/%m/%d-%T',time); + + print "Importing batch..." if $opt{'v'}; + my $error = FS::cdr::batch_import( { + 'file' => $temp->filename, + 'format' => $format, + 'batch_namevalue' => $batchname, + } ); + + if ( $error ) { + $dbh->rollback; + print "error: $error"; + exit(-2); + } +} +$dbh->commit; +print "done.\n"; +exit(0); + +sub usage { + my $err = @_ ? shift."\n\n" : ''; +$err."Usage: +freeside-vitelity-cdrimport [ -v ] [ -k ] + -s date -e date + username + [ exportnum ] +"; +} + diff --git a/FS/bin/freeside-voipinnovations-cdrimport b/FS/bin/freeside-voipinnovations-cdrimport new file mode 100755 index 0000000..484b330 --- /dev/null +++ b/FS/bin/freeside-voipinnovations-cdrimport @@ -0,0 +1,129 @@ +#!/usr/bin/perl + +use strict; +use Getopt::Std; +use Date::Format; +use File::Temp 'tempdir'; +use Net::FTP; +use FS::UID qw(adminsuidsetup datasrc dbh); +use FS::cdr; +use FS::cdr_batch; +use FS::Record qw(qsearch qsearchs); +use Date::Format 'time2str'; +use Date::Parse 'str2time'; + + +### +# parse command line +### + +use vars qw( $opt_d $opt_v $opt_c $opt_s $opt_e $opt_a ); +getopts('dvc:s:e:a'); + +my ($user, $login, $password) = @ARGV; +$user and $login and $password or die &usage; + +my $dbh = adminsuidsetup $user; +$FS::UID::AutoCommit = 0; + +# index already-downloaded batches +my @previous = qsearch({ + 'table' => 'cdr_batch', + 'hashref' => { 'cdrbatch' => {op=>'like', value=>'voip_innovations%'} }, + 'order_by' => 'ORDER BY cdrbatch DESC', +}); +my %exists = map {$_->cdrbatch => 1} @previous; + +my $tempdir = tempdir( CLEANUP => !$opt_v ); + +my $format = 'voip_innovations'; +my $hostname = 'cdrs.globalpopsvoip.com'; + +my $ftp = Net::FTP->new($hostname, Debug => $opt_d) + or die "Can't connect to $hostname: $@\n"; + +$ftp->login($login, $password) + or die "Login failed: ".$ftp->message."\n"; + +### +# get the file list +### + +warn "Retrieving directory listing\n" if $opt_v; + +$ftp->cwd('/'); +my @dirs = $ftp->ls(); +warn scalar(@dirs)." directories found.\n" if $opt_v; +# apply date range +if ( $opt_a ) { + my $most_recent = $previous[0]; + if ($most_recent) { + if ($most_recent->cdrbatch =~ /^voip_innovations-(\d+)/) { + my $date = $1; + warn "limiting to dates > $date (from most recent batch)\n" if $opt_v; + @dirs = grep {$_ > $date} @dirs; + } + } # else download them all +} +if ( $opt_s ) { + # start date + # normalize date format + $opt_s = time2str('%Y%m%d', str2time($opt_s)) if $opt_s =~ /\D/; + warn "limiting to dates > $opt_s\n" if $opt_v; + @dirs = grep {$_ > $opt_s} @dirs; +} +if ( $opt_e ) { + # end date + $opt_e = time2str('%Y%m%d', str2time($opt_e)) if $opt_e =~ /\D/; + warn "limiting to dates < $opt_e\n" if $opt_v; + @dirs = grep {$_ < $opt_e} @dirs; +} +warn scalar(@dirs) ." to be downloaded\n" if $opt_v; +foreach my $dir (@dirs) { + $ftp->cwd($dir); + foreach my $file ($ftp->ls) { + warn "downloading $file\n" if $opt_v; + $ftp->get($file, "$tempdir/$file"); + warn "processing $file\n" if $opt_v; + + # "voip_innovations-20130628/20130628_20130628.CDR" + my $batchname = "$format-$dir/$file"; + if ($exists{$batchname}) { + warn "already imported $file\n"; + next; + } + my $import_options = { + 'file' => "$tempdir/$file", + 'format' => $format, + 'batch_namevalue' => $batchname, + 'empty_ok' => 1, + }; + $import_options->{'cdrtypenum'} = $opt_c if $opt_c; + + my $error = FS::cdr::batch_import($import_options); + + if ( $error ) { + die "error processing $dir/$file: $error\n"; + } + } + $ftp->cwd('..'); +} +warn "finished\n"; +$dbh->commit; + +### +# subs +### + +sub usage { + "Usage: \n freeside-voip_innovations-cdrimport user login password\n [ options ] + Options: + -v: be verbose + -d: enable FTP debugging (very noisy) + -c num: apply a cdrtypenum to the imported CDRs + -s date: start date + -e date: end date + -a: automatically choose start date from most recently downloaded batch + "; +} + diff --git a/FS/t/cust_bill_event.t b/FS/t/cust_bill_event.t deleted file mode 100644 index 0e2ca3e..0000000 --- a/FS/t/cust_bill_event.t +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN { $| = 1; print "1..1\n" } -END {print "not ok 1\n" unless $loaded;} -use FS::cust_bill_event; -$loaded=1; -print "ok 1\n"; diff --git a/FS/t/part_bill_event.t b/FS/t/part_bill_event.t deleted file mode 100644 index 5626a9f..0000000 --- a/FS/t/part_bill_event.t +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN { $| = 1; print "1..1\n" } -END {print "not ok 1\n" unless $loaded;} -use FS::part_bill_event; -$loaded=1; -print "ok 1\n"; diff --git a/httemplate/browse/part_bill_event.cgi b/httemplate/browse/part_bill_event.cgi deleted file mode 100755 index 11bc14e..0000000 --- a/httemplate/browse/part_bill_event.cgi +++ /dev/null @@ -1,122 +0,0 @@ -<% include('/elements/header.html', 'Invoice Event Listing') %> - - <FONT SIZE="+1">Invoice events are the deprecated, old-style actions taken on open invoices. Any events still listed here should be migrated to new-style events.</FONT><BR><BR> - -<A HREF="<% $p %>edit/part_bill_event.cgi"><I>Add a new invoice event</I></A> -<BR><BR> - -<% $total %> events -<% $cgi->param('showdisabled') - ? do { $cgi->param('showdisabled', 0); - '( <a href="'. $cgi->self_url. '">hide disabled events</a> )'; } - : do { $cgi->param('showdisabled', 1); - '( <a href="'. $cgi->self_url. '">show disabled events</a> )'; } -%> -<BR><BR> -% tie my %payby, 'Tie::IxHash', FS::payby->cust_payby2longname; -% tie my %freq, 'Tie::IxHash', '1d' => 'daily', '1m' => 'monthly'; -% foreach my $payby ( keys %payby ) { -% my $oldfreq = ''; -% -% my @payby_part_bill_event = -% grep { $payby eq $_->payby } -% sort { ( $a->freq || '1d') cmp ( $b->freq || '1d' ) # for now -% || $a->seconds <=> $b->seconds -% || $a->weight <=> $b->weight -% || $a->eventpart <=> $b->eventpart -% } -% @part_bill_event; -% -% -% if ( @payby_part_bill_event ) { - - - <% include('/elements/table-grid.html') %> -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor; -% -% -% foreach my $part_bill_event ( @payby_part_bill_event ) { -% my $url = "${p}edit/part_bill_event.cgi?". $part_bill_event->eventpart; -% my $delay = duration_exact($part_bill_event->seconds); -% ( my $plandata = $part_bill_event->plandata ) =~ s/\n/<BR>/go; -% my $freq = $part_bill_event->freq || '1d'; -% my $reason = $part_bill_event->reasontext ; -% -% if ( $oldfreq ne $freq ) { - - - <TR> - <TH CLASS="grid" BGCOLOR="#999999" COLSPAN=<% $cgi->param('showdisabled') ? 7 : 8 %>><% ucfirst($freq{$freq}) %> event tests for <FONT SIZE="+1"><I><% $payby{$payby} %> customers</I></FONT></TH> - </TR> - - <TR> - <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=<% $cgi->param('showdisabled') ? 2 : 3 %>>Event</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">After</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Action</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Reason</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Options</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Code</TH> - </TR> -% -% $oldfreq = $freq; -% $bgcolor = ''; -% -% } -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } -% - - - <TR> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<% $url %>"> - <% $part_bill_event->eventpart %></A></TD> -% unless ( $cgi->param('showdisabled') ) { - - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <% $part_bill_event->disabled ? 'DISABLED' : '' %></TD> -% } - - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<% $url %>"> - <% $part_bill_event->event %></A></TD> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <% $delay %></TD> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <% $part_bill_event->plan %></TD> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <% $reason %></TD> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> - <% $plandata %></TD> - <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><FONT SIZE="-1"> - <% $part_bill_event->eventcode %></FONT></TD> - </TR> -% } - - </TABLE> - <BR><BR> -% } -% } - -<% include('/elements/footer.html') %> - -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); - -my %search; -if ( $cgi->param('showdisabled') ) { -%search = (); -} else { -%search = ( 'disabled' => '' ); -} - -my @part_bill_event = qsearch('part_bill_event', \%search ); -my $total = scalar(@part_bill_event); - -</%init> diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index fa392bb..d25e887 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -18,6 +18,27 @@ <% &ntable("#cccccc") %> % my $curuser = $FS::CurrentUser::CurrentUser; + +% ### +% # complimentry flag +% ### + +% if ( $curuser->access_right('Complimentary customer') ) { + + <TR> + <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="complimentary" VALUE="Y" <% $cust_main->complimentary eq "Y" ? 'CHECKED' : '' %>>Complimentary customer + </TR> + +% } else { + + <INPUT TYPE="hidden" NAME="complimentary" VALUE="<% $cust_main->complimentary eq 'Y' ? 'Y' : '' %>"> + +% } + +% ### +% # tax exemptions +% ### + % my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); % if ( $conf->exists('cust_class-tax_exempt') % || $conf->exists('tax-cust_exempt-groups-require_individual_nums') @@ -31,7 +52,7 @@ % } else { <TR> - <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="tax" VALUE="Y" <% $cust_main->tax eq "Y" ? 'CHECKED' : '' %>> Tax Exempt<% @exempt_groups ? ' (all taxes)' : '' %></TD> + <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="tax" VALUE="Y" <% $cust_main->tax eq "Y" ? 'CHECKED' : '' %>> Tax Exempt<% @exempt_groups ? ' (all taxes)' : '' %></TD> </TR> % } @@ -48,10 +69,14 @@ % } % } +% ### +% # postal invoices +% ### + % unless ( $conf->exists('emailinvoiceonly') ) { <TR> - <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST" <% + <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST" <% ( grep { $_ eq 'POST' } @invoicing_list ) @@ -65,8 +90,12 @@ % } +% ### +% # email invoices +% ### + <TR> - <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="invoice_email" VALUE="Y" <% + <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="invoice_email" VALUE="Y" <% ( $cust_main->invoice_noemail eq 'Y' ) ? '' @@ -93,6 +122,10 @@ </TR> % } +% ### +% # prorate_day +% ### + % if ( $conf->exists('cust_main-select-prorate_day') ) { <TR> <TD ALIGN="right" WIDTH="200"><% mt('Prorate day (1-28)') |h %> </TD> @@ -104,6 +137,10 @@ <INPUT TYPE="hidden" NAME="prorate_day" VALUE="<% $cust_main->prorate_day %>"> % } +% ### +% # billday +% ### + <TR> <TD ALIGN="right" WIDTH="200"><% mt('Charge card/e-check on this day of the month') |h %> </TD> <TD> @@ -124,6 +161,10 @@ % $ret; % } +% ### +% # invoice_terms +% ### + <TR> <TD ALIGN="right" WIDTH="200"><% mt('Invoice terms') |h %> </TD> <TD WIDTH="408"> @@ -134,6 +175,10 @@ </TD> </TR> +% ### +% # credit_limit +% ### + <TR> <TD ALIGN="right" WIDTH="200"><% mt('Credit limit') |h %> </TD> <TD WIDTH="408"> @@ -162,6 +207,10 @@ function toggle(obj) { </TD> </TR> +% ### +% # CDR flags / options +% ### + % if ( $conf->exists('voip-cust_cdr_spools') ) { <TR> <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="spool_cdr" VALUE="Y" <% $cust_main->spool_cdr eq "Y" ? 'CHECKED' : '' %>> <% mt('Spool CDRs') |h %></TD> @@ -213,6 +262,10 @@ function toggle(obj) { <INPUT TYPE="hidden" NAME="cdr_termination_percentage" VALUE="<% $cust_main->cdr_termination_percentage %>"> % } +% ### +% # Invoicing currency +% ### + %my @currencies = $conf->config('currencies'); %if ( scalar(@currencies) ) { % unshift @currencies, ''; #default @@ -229,6 +282,9 @@ function toggle(obj) { &> % } +% ### +% # Invoicing locale +% ### %my @available_locales = $conf->config('available-locales'); %if ( scalar(@available_locales) ) { @@ -268,11 +324,6 @@ my $conf = new FS::Conf; my $money_char = $conf->config('money_char') || '$'; -my @payby = grep /\w/, $conf->config('payby'); -#@payby = (qw( CARD DCRD CHEK DCHK BILL CASH WEST COMP )) -@payby = (qw( CARD DCRD CHEK DCHK BILL CASH COMP )) - unless @payby; - my $show_term = ''; if ( $cust_main->custnum ) { #false laziness w/view/cust_main/billing.html diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi deleted file mode 100755 index c0ff386..0000000 --- a/httemplate/edit/part_bill_event.cgi +++ /dev/null @@ -1,570 +0,0 @@ -<% include('/elements/header.html', - "$action Invoice Event Definition", - menubar( - 'View all invoice events' => popurl(2). 'browse/part_bill_event.cgi', - ) - ) -%> - -<% include('/elements/error.html') %> - -<FORM ACTION="<% popurl(1) %>process/part_bill_event.cgi" NAME="editEvent" METHOD=POST> -<INPUT TYPE="hidden" NAME="eventpart" VALUE="<% $part_bill_event->eventpart %>"> -Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %> - -<% ntable("#cccccc",2) %> - - <TR> - <TD ALIGN="right">Event name </TD> - <TD><INPUT TYPE="text" NAME="event" VALUE="<% $hashref->{event} %>"></TD> - </TR> - - <TR> - <TD ALIGN="right">For </TD> - <TD> - <SELECT NAME="payby" <% $hashref->{eventpart} ? '' : 'MULTIPLE SIZE=7'%>> -% tie my %payby, 'Tie::IxHash', FS::payby->cust_payby2longname; -% foreach my $payby ( keys %payby ) { - <OPTION VALUE="<% $payby %>"<% ($part_bill_event->payby eq $payby) ? ' SELECTED' : '' %>><% $payby{$payby} %></OPTION> -% } - </SELECT> customers - </TD> - </TR> -% my $days = $hashref->{seconds}/86400; - - - <TR> - <TD ALIGN="right">After</TD> - <TD><INPUT TYPE="text" NAME="days" VALUE="<% $days %>"> days</TD> - </TR> - - <TR> - <TD ALIGN="right">Test event</TD> - <TD> - <SELECT NAME="freq"> -% tie my %freq, 'Tie::IxHash', '1d' => 'daily', '1m' => 'monthly'; -% foreach my $freq ( keys %freq ) { -% - - - <OPTION VALUE="<% $freq %>"<% ($part_bill_event->freq eq $freq) ? ' SELECTED' : '' %>><% $freq{$freq} %></OPTION> -% } - - - </SELECT> - </TD> - </TR> - - - <TR> - <TD ALIGN="right">Disabled</TD> - <TD> - <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>> - </TD> - </TR> - - <TR> - <TD VALIGN="top" ALIGN="right">Action</TD> - <TD> -% -% -%#print ntable(); -% -%sub select_pkgpart { -% my $label = shift; -% my $plandata = shift; -% my %selected = map { $_=>1 } split(/,\s*/, $plandata->{$label}); -% qq(<SELECT NAME="$label" MULTIPLE>). -% join("\n", map { -% '<OPTION VALUE="'. $_->pkgpart. '"'. -% ( $selected{$_->pkgpart} ? ' SELECTED' : '' ). -% '>'. $_->pkg_comment -% } qsearch('part_pkg', { 'disabled' => '' } ) ). -% '</SELECT>'; -%} -% -%sub select_agentnum { -% my $plandata = shift; -% #my $agentnum = $plandata->{'agentnum'}; -% my %agentnums = map { $_=>1 } split(/,\s*/, $plandata->{'agentnum'}); -% '<SELECT NAME="agentnum" MULTIPLE>'. -% join("\n", map { -% '<OPTION VALUE="'. $_->agentnum. '"'. -% ( $agentnums{$_->agentnum} ? ' SELECTED' : '' ). -% '>'. $_->agent -% } qsearch('agent', { 'disabled' => '' } ) ). -% '</SELECT>'; -%} -% -%sub honor_dundate { -% my $label = shift; -% my $plandata = shift; -% '<TABLE>'. -% '<TR><TD ALIGN="right">Allow delay until dun date? </TD>'. -% qq(<TD><INPUT TYPE="checkbox" NAME="$label" VALUE="$label => 1," ). -% ( $plandata->{$label} eq "$label => 1," ? 'CHECKED' : '' ). -% '>'. -% '</TD></TR>'. -% '</TABLE>' -%} -% -%my $conf = new FS::Conf; -%my $money_char = $conf->config('money_char') || '$'; -% -%my $late_taxclass = ''; -%my $late_percent_taxclass = ''; -%if ( $conf->exists('enable_taxclasses') ) { -% $late_taxclass = -% '<BR>Taxclass '. -% include('/elements/select-taxclass.html', -% 'curr_value' => '%%%late_taxclass%%%', -% 'name' => 'late_taxclass' ); -% $late_percent_taxclass = -% '<BR>Taxclass '. -% include('/elements/select-taxclass.html', -% 'curr_value' => '%%%late_percent_taxclass%%%', -% 'name' => 'late_percent_taxclass' ); -%} -% -%#this is pretty kludgy right here. -%tie my %events, 'Tie::IxHash', -% -% 'fee' => { -% 'name' => 'Late fee (flat)', -% 'code' => '$cust_main->charge( %%%charge%%%, \'%%%reason%%%\', \'$%%%charge%%%\', \'%%%late_taxclass%%%\' );', -% 'html' => -% 'Amount <INPUT TYPE="text" SIZE="7" NAME="charge" VALUE="%%%charge%%%">'. -% '<BR>Reason <INPUT TYPE="text" NAME="reason" VALUE="%%%reason%%%">'. -% $late_taxclass, -% 'weight' => 10, -% }, -% 'fee_percent' => { -% 'name' => 'Late fee (percentage)', -% 'code' => '$cust_main->charge( sprintf(\'%.2f\', $cust_bill->owed * %%%percent%%% / 100 ), \'%%%percent_reason%%%\', \'%%%percent%%% percent\', \'%%%late_percent_taxclass%%%\' );', -% 'html' => -% 'Percent <INPUT TYPE="text" SIZE="2" NAME="percent" VALUE="%%%percent%%%">%'. -% '<BR>Reason <INPUT TYPE="text" NAME="percent_reason" VALUE="%%%percent_reason%%%">'. -% $late_percent_taxclass, -% 'weight' => 10, -% }, -% 'suspend' => { -% 'name' => 'Suspend', -% 'code' => '$cust_main->suspend(reason => %%%sreason%%%, %%%honor_dundate%%% );', -% 'html' => sub { &honor_dundate('honor_dundate', @_) }, -% 'weight' => 10, -% 'reason' => 'S', -% }, -% 'suspend-if-balance' => { -% 'name' => 'Suspend if balance (this invoice and previous) over', -% 'code' => '$cust_bill->cust_suspend_if_balance_over( %%%balanceover%%%, reason => %%%sreason%%%, %%%balance_honor_dundate%%% );', -% 'html' => sub { " $money_char ". '<INPUT TYPE="text" SIZE="7" NAME="balanceover" VALUE="%%%balanceover%%%"> '. &honor_dundate('balance_honor_dundate', @_) }, -% 'weight' => 10, -% 'reason' => 'S', -% }, -% 'suspend-if-pkgpart' => { -% 'name' => 'Suspend packages', -% 'code' => '$cust_main->suspend_if_pkgpart({pkgparts => [%%%if_pkgpart%%%,], reason => %%%sreason%%%, %%%if_pkgpart_honor_dundate%%% });', -% 'html' => sub { &select_pkgpart('if_pkgpart', @_). &honor_dundate('if_pkgpart_honor_dundate', @_) }, -% 'weight' => 10, -% 'reason' => 'S', -% }, -% 'suspend-unless-pkgpart' => { -% 'name' => 'Suspend packages except', -% 'code' => '$cust_main->suspend_unless_pkgpart({unless_pkgpart => [%%%unless_pkgpart%%%], reason => %%%sreason%%%, %%%unless_pkgpart_honor_dundate%%% });', -% 'html' => sub { &select_pkgpart('unless_pkgpart', @_). &honor_dundate('unless_pkgpart_honor_dundate' => @_) }, -% 'weight' => 10, -% 'reason' => 'S', -% }, -% 'cancel' => { -% 'name' => 'Cancel', -% 'code' => '$cust_main->cancel(reason => %%%creason%%%);', -% 'weight' => 80, #10, -% 'reason' => 'C', -% }, -% -% 'addpost' => { -% 'name' => 'Add postal invoicing', -% 'code' => '$cust_main->invoicing_list_addpost(); "";', -% 'weight' => 20, -% }, -% -% 'comp' => { -% 'name' => 'Pay invoice with a complimentary "payment"', -% 'code' => '$cust_bill->comp();', -% 'weight' => 90, #30, -% }, -% -% 'credit' => { -% 'name' => "Create and apply a credit for the customer's balance (i.e. write off as bad debt)", -% 'code' => '$cust_main->credit( $cust_main->balance, \'%%%credit_reason%%%\' );', -% 'html' => '<INPUT TYPE="text" NAME="credit_reason" VALUE="%%%credit_reason%%%">', -% 'weight' => 30, -% }, -% -% 'realtime-card' => { -% 'name' => 'Run card with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', -% 'code' => '$cust_bill->realtime_card();', -% 'weight' => 30, -% }, -% -% 'realtime-check' => { -% 'name' => 'Run check with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', -% 'code' => '$cust_bill->realtime_ach();', -% 'weight' => 30, -% }, -% -% 'realtime-lec' => { -% 'name' => 'Run phone bill ("LEC") billing with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', -% 'code' => '$cust_bill->realtime_lec();', -% 'weight' => 30, -% }, -% -% 'batch-card' => { -% 'name' => 'Add card or check to a pending batch', -% 'code' => '$cust_bill->batch_card(%options);', -% 'weight' => 40, -% }, -% -% -% #'retriable' => { -% # 'name' => 'Mark batched card event as retriable', -% # 'code' => '$cust_pay_batch->retriable();', -% # 'weight' => 60, -% #}, -% -% 'send' => { -% 'name' => 'Send invoice (email/print/fax)', -% 'code' => '$cust_bill->send();', -% 'weight' => 50, -% }, -% -% 'send_email' => { -% 'name' => 'Send invoice (email only)', -% 'code' => '$cust_bill->email();', -% 'weight' => 50, -% }, -% -% 'send_alternate' => { -% 'name' => 'Send invoice (email/print/fax) with alternate template', -% 'code' => '$cust_bill->send(\'%%%templatename%%%\');', -% 'html' => -% '<INPUT TYPE="text" NAME="templatename" VALUE="%%%templatename%%%">', -% 'weight' => 50, -% }, -% -% 'send_if_newest' => { -% 'name' => 'Send invoice (email/print/fax) with alternate template, if it is still the newest invoice (useful for late notices - set to 31 days or later)', -% 'code' => '$cust_bill->send_if_newest(\'%%%if_newest_templatename%%%\');', -% 'html' => -% '<INPUT TYPE="text" NAME="if_newest_templatename" VALUE="%%%if_newest_templatename%%%">', -% 'weight' => 50, -% }, -% -% 'send_agent' => { -% 'name' => 'Send invoice (email/print/fax) ', -% 'code' => '$cust_bill->send( \'%%%agent_templatename%%%\', -% [ %%%agentnum%%% ], -% \'%%%agent_invoice_from%%%\', -% %%%agent_balanceover%%% -% );', -% 'html' => sub { -% '<TABLE BORDER=0> -% <TR> -% <TD ALIGN="right">only for agent(s) </TD> -% <TD>'. &select_agentnum(@_). '</TD> -% </TR> -% <TR> -% <TD ALIGN="right">with template </TD> -% <TD> -% <INPUT TYPE="text" NAME="agent_templatename" VALUE="%%%agent_templatename%%%"> -% </TD> -% </TR> -% <TR> -% <TD ALIGN="right">email From: </TD> -% <TD> -% <INPUT TYPE="text" NAME="agent_invoice_from" VALUE="%%%agent_invoice_from%%%"> -% </TD> -% </TR> -% <TR> -% <TD ALIGN="right">if balance (this invoice and previous) over -% </TD> -% <TD> -% '. $money_char. '<INPUT TYPE="text" SIZE="7" NAME="agent_balanceover" VALUE="%%%agent_balanceover%%%"> -% </TD> -% </TR> -% </TABLE>'; -% }, -% 'weight' => 50, -% }, -% -% 'send_csv_ftp' => { -% 'name' => 'Upload CSV invoice data to an FTP server', -% 'code' => '$cust_bill->send_csv( protocol => \'ftp\', -% server => \'%%%ftpserver%%%\', -% username => \'%%%ftpusername%%%\', -% password => \'%%%ftppassword%%%\', -% dir => \'%%%ftpdir%%%\', -% \'format\' => \'%%%ftpformat%%%\', -% );', -% 'html' => -% '<TABLE BORDER=0>'. -% '<TR><TD ALIGN="right">Format ("default" or "billco"): </TD>'. -% '<TD>'. -% '<!--'. -% '<SELECT NAME="ftpformat">'. -% '<OPTION VALUE="default">Default'. -% '<OPTION VALUE="billco">Billco'. -% '</SELECT>'. -% '-->'. -% '<INPUT TYPE="text" NAME="ftpformat" VALUE="%%%ftpformat%%%">'. -% '</TD></TR>'. -% '<TR><TD ALIGN="right">FTP server: </TD>'. -% '<TD><INPUT TYPE="text" NAME="ftpserver" VALUE="%%%ftpserver%%%">'. -% '</TD></TR>'. -% '<TR><TD ALIGN="right">FTP username: </TD><TD>'. -% '<INPUT TYPE="text" NAME="ftpusername" VALUE="%%%ftpusername%%%">'. -% '</TD></TR>'. -% '<TR><TD ALIGN="right">FTP password: </TD><TD>'. -% '<INPUT TYPE="text" NAME="ftppassword" VALUE="%%%ftppassword%%%">'. -% '</TD></TR>'. -% '<TR><TD ALIGN="right">FTP directory: </TD>'. -% '<TD><INPUT TYPE="text" NAME="ftpdir" VALUE="%%%ftpdir%%%">'. -% '</TD></TR>'. -% '</TABLE>', -% 'weight' => 50, -% }, -% -% 'spool_csv' => { -% 'name' => 'Spool CSV invoice data', -% 'code' => '$cust_bill->spool_csv( -% \'format\' => \'%%%spoolformat%%%\', -% \'dest\' => \'%%%spooldest%%%\', -% \'balanceover\' => \'%%%spoolbalanceover%%%\', -% \'agent_spools\' => \'%%%spoolagent_spools%%%\', -% );', -% 'html' => sub { -% my $plandata = shift; -% -% my $html = -% '<TABLE BORDER=0>'. -% '<TR><TD ALIGN="right">Format: </TD>'. -% '<TD>'. -% '<SELECT NAME="spoolformat">'; -% -% foreach my $option (qw( default billco )) { -% $html .= qq(<OPTION VALUE="$option"); -% $html .= ' SELECTED' if $option eq $plandata->{'spoolformat'}; -% $html .= ">\u$option"; -% } -% -% $html .= -% '</SELECT>'. -% '</TD></TR>'. -% '<TR><TD ALIGN="right">For destination: </TD>'. -% '<TD>'. -% '<SELECT NAME="spooldest">'; -% -% tie my %dest, 'Tie::IxHash', -% '' => '(all)', -% 'POST' => 'Postal Mail', -% 'EMAIL' => 'Email', -% 'FAX' => 'Fax', -% ; -% -% foreach my $dest (keys %dest) { -% $html .= qq(<OPTION VALUE="$dest"); -% $html .= ' SELECTED' if $dest eq $plandata->{'spooldest'}; -% $html .= '>'. $dest{$dest}; -% } -% -% $html .= -% '</SELECT>'. -% '</TD></TR>'. -% -% '<TR>'. -% '<TD ALIGN="right">if balance (this invoice and previous) over </TD>'. -% '<TD>'. -% "$money_char ". -% '<INPUT TYPE="text" SIZE="7" NAME="spoolbalanceover" VALUE="%%%spoolbalanceover%%%">'. -% '</TD>'. -% '<TR><TD ALIGN="right">Individual per-agent spools? </TD>'. -% '<TD><INPUT TYPE="checkbox" NAME="spoolagent_spools" VALUE="1" '. -% ( $plandata->{'spoolagent_spools'} ? 'CHECKED' : '' ). -% '>'. -% '</TD></TR>'. -% '</TABLE>'; -% -% $html; -% }, -% 'weight' => 50, -% }, -% -% 'bill' => { -% 'name' => 'Generate invoices (normally only used with a <i>Late Fee</i> event)', -% 'code' => '$cust_main->bill();', -% 'weight' => 60, -% }, -% -% 'apply' => { -% 'name' => 'Apply unapplied payments and credits', -% 'code' => '$cust_main->apply_payments_and_credits; "";', -% 'weight' => 70, -% }, -% -%; -% -<SCRIPT TYPE="text/javascript">var myreasons = new Array();</SCRIPT> -%foreach my $event ( keys %events ) { -% my %plandata = map { /^(\w+) (.*)$/; ($1, $2); } -% split(/\n/, $part_bill_event->plandata); -% my $html = $events{$event}{html}; -% if ( ref($html) eq 'CODE' ) { -% $html = &{$html}(\%plandata); -% } -% while ( $html =~ /%%%(\w+)%%%/ ) { -% my $field = $1; -% $html =~ s/%%%$field%%%/$plandata{$field}/; -% } -% -<SCRIPT TYPE="text/javascript">myreasons.push('<% $events{$event}{reason} %>'); -</SCRIPT> -% if ($event eq $part_bill_event->plan){ -% $currentreasonclass=$events{$event}{reason}; -% } -% print ntable( "#cccccc", 2). -% qq!<TR><TD><INPUT TYPE="radio" NAME="plan_weight_eventcode" !; -% print "CHECKED " if $event eq $part_bill_event->plan; -% print qq!onClick="showhide_table()" !; -% print qq!VALUE="!. $event. ":". $events{$event}{weight}. ":". -% encode_entities($events{$event}{code}). -% qq!">$events{$event}{name}</TD>!; -% print '<TD>'. $html. '</TD>' if $html; -% print qq!</TR>!; -% print '</TABLE>'; -% print qq!<HR WIDTH="90%">!; -%} -% -% if ($currentreasonclass eq 'C'){ -% if ($cgi->param('creason') =~ /^(-?\d+)$/){ -% $creason = $1; -% }else{ -% $creason = $part_bill_event->reason; -% } -% if ($cgi->param('newcreasonT') =~ /^(\d+)$/){ -% $newcreasonT = $1; -% } -% if ($cgi->param('newcreason') =~ /^([\w\s]+)$/){ -% $newcreason = $1; -% } -% }elsif ($currentreasonclass eq 'S'){ -% if ($cgi->param('sreason') =~ /^(-?\d+)$/){ -% $sreason = $1; -% }else{ -% $sreason = $part_bill_event->reason; -% } -% if ($cgi->param('newsreasonT') =~ /^(\d+)$/){ -% $newsreasonT = $1; -% } -% if ($cgi->param('newsreason') =~ /^([\w\s]+)$/){ -% $newsreason = $1; -% } -% } -% - -</TD></TR> -</TABLE> - -<SCRIPT TYPE="text/javascript"> - function showhide_table() - { - for(i=0;i<document.editEvent.plan_weight_eventcode.length;i++){ - if (document.editEvent.plan_weight_eventcode[i].checked == true){ - currentevent=i; - } - } - if(myreasons[currentevent] == 'C'){ - document.getElementById('Ctable').style.display = 'inline'; - document.getElementById('Stable').style.display = 'none'; - }else if(myreasons[currentevent] == 'S'){ - document.getElementById('Ctable').style.display = 'none'; - document.getElementById('Stable').style.display = 'inline'; - }else{ - document.getElementById('Ctable').style.display = 'none'; - document.getElementById('Stable').style.display = 'none'; - } - } -</SCRIPT> - -<TABLE BGCOLOR="#cccccc" BORDER=0 WIDTH="100%"> -<TR><TD> -<TABLE BORDER=0 id="Ctable" style="display:<% $currentreasonclass eq 'C' ? 'inline' : 'none' %>"> -<% include('/elements/tr-select-reason.html', - 'field' => 'creason', - 'reason_class' => 'C', - 'curr_value' => $creason, - 'init_type' => $newcreasonT, - 'init_newreason' => $newcreason - ) -%> -</TABLE> -</TR></TD> -</TABLE> - -<TABLE BGCOLOR="#cccccc" BORDER=0 WIDTH="100%"> -<TR><TD> -<TABLE BORDER=0 id="Stable" style="display:<% $currentreasonclass eq 'S' ? 'inline' : 'none' %>"> -<% include('/elements/tr-select-reason.html', - 'field' => 'sreason', - 'reason_class' => 'S', - 'curr_value' => $sreason, - 'init_type' => $newsreasonT, - 'init_newreason' => $newsreason - ) -%> -</TABLE> -</TR></TD> -</TABLE> - -% -%print qq!<INPUT TYPE="submit" VALUE="!, -% $hashref->{eventpart} ? "Apply changes" : "Add invoice event", -% qq!">!; -% - - - </FORM> - -<% include('/elements/footer.html') %> - -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); - -if ( $cgi->param('eventpart') && $cgi->param('eventpart') =~ /^(\d+)$/ ) { - $cgi->param('eventpart', $1); -} else { - $cgi->param('eventpart', ''); -} - -my ($creason, $newcreasonT, $newcreason); -my ($sreason, $newsreasonT, $newsreason); - -my ($query) = $cgi->keywords; -my $action = ''; -my $part_bill_event = ''; -my $currentreasonclass = ''; -if ( $cgi->param('error') ) { - $part_bill_event = new FS::part_bill_event ( { - map { $_, scalar($cgi->param($_)) } fields('part_bill_event') - } ); -} -if ( $query && $query =~ /^(\d+)$/ ) { - $part_bill_event ||= qsearchs('part_bill_event',{'eventpart'=>$1}); -} else { - $part_bill_event ||= new FS::part_bill_event {}; -} -$action ||= $part_bill_event->eventpart ? 'Edit' : 'Add'; -my $hashref = $part_bill_event->hashref; - -</%init> diff --git a/httemplate/edit/process/part_bill_event.cgi b/httemplate/edit/process/part_bill_event.cgi deleted file mode 100755 index eb0529b..0000000 --- a/httemplate/edit/process/part_bill_event.cgi +++ /dev/null @@ -1,106 +0,0 @@ -%if ( $error ) { -% $cgi->param('error', $error); -<% $cgi->redirect(popurl(2). "part_bill_event.cgi?". $cgi->query_string ) %> -%} else { -<% $cgi->redirect(popurl(3)."browse/part_bill_event.cgi") %> -%} -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); - -my $eventpart = $cgi->param('eventpart'); - -my $old = qsearchs('part_bill_event',{'eventpart'=>$eventpart}) if $eventpart; - -#s/days/seconds/ -$cgi->param('seconds', int( $cgi->param('days') * 86400 ) ); - -my $error; -if ( ! $cgi->param('plan_weight_eventcode') ) { - $error = "Must select an action"; -} else { - - $cgi->param('plan_weight_eventcode') =~ /^([\w\-]+):(\d+):(.*)$/s - or die "illegal plan_weight_eventcode:". - $cgi->param('plan_weight_eventcode'); - $cgi->param('plan', $1); - $cgi->param('weight', $2); - my $eventcode = $3; - my $plandata = ''; - - my $rnum; - my $rtype; - my $reasonm; - my $class = ''; - $class='c' if ($eventcode =~ /cancel/); - $class='s' if ($eventcode =~ /suspend/); - if ($class) { - $cgi->param("${class}reason") =~ /^(-?\d+)$/ - or $error = "Invalid ${class}reason"; - $rnum = $1; - if ($rnum == -1) { - $cgi->param("new${class}reasonT") =~ /^(\d+)$/ - or $error = "Invalid new${class}reasonT"; - $rtype = $1; - $cgi->param("new${class}reason") =~ /^([\s\w]+)$/ - or $error = "Invalid new${class}reason"; - $reasonm = $1; - } - } - - if ($rnum == -1 && !$error) { - my $reason = new FS::reason ({ 'reason' => $reasonm, - 'reason_type' => $rtype, - }); - $error = $reason->insert; - unless ($error) { - $rnum = $reason->reasonnum; - $cgi->param("${class}reason", $rnum); - $cgi->param("new${class}reason", ''); - $cgi->param("new${class}reasonT", ''); - } - } - - while ( $eventcode =~ /%%%(\w+)%%%/ ) { - my $field = $1; - my $value = join(', ', $cgi->param($field) ); - $cgi->param($field, $value); #in case it errors out - $eventcode =~ s/%%%$field%%%/$value/; - $plandata .= "$field $value\n"; - } - $cgi->param('eventcode', $eventcode); - $cgi->param('plandata', $plandata); - - unless($error) { - - if ( $eventpart ) { - - my $new = new FS::part_bill_event ( { - map { $_ => scalar($cgi->param($_)) } - fields('part_bill_event'), - } ); - $new->setfield('reason' => $rnum); - $error = $new->replace($old); - - } else { - - foreach my $payby ( $cgi->param('payby') ) { - my $new = new FS::part_bill_event ( { - map { $_ => scalar($cgi->param($_)) } - grep { $_ ne 'payby' } - fields('part_bill_event') - } ); - $new->setfield('payby' => $payby); - $new->setfield('reason' => $rnum ); - $error = $new->insert; - last if $error; - } - - } - - } - -} - -</%init> diff --git a/httemplate/elements/cust_payby.html b/httemplate/elements/cust_payby.html index 20ad343..0eb3e3e 100644 --- a/httemplate/elements/cust_payby.html +++ b/httemplate/elements/cust_payby.html @@ -107,15 +107,17 @@ </SELECT> <BR><FONT SIZE="-1"><% mt('Account type') |h %></FONT> </TD> - -% my( $account, $aba ) = split('@', -% ( $cgi->param($name.'_payby') || $cust_payby->payby ) =~ /^(CHEK|DCHK)$/ -% ? $cgi->param($name.'_payinfo') -% : $cust_payby->payinfo -% ); -% my $branch = ''; -% ($branch,$aba) = split('\.',$aba) -% if $echeck_country eq 'CA'; + +% my ( $account, $aba, $branch ) = ( '', '', '' ); +% if ( $cgi->param($name.'_payby') =~ /^(CHEK|DCHK)$/ ) { +% $account = $cgi->param($name.'_payinfo1'); +% $aba = $cgi->param($name.'_payinfo2'); +% $branch = $cgi->param($name.'_payinfo3'); +% } elsif ( $cust_payby->payby =~ /^(CHEK|DCHK)$/ ) { +% ( $account, $aba ) = split('@', $cust_payby->payinfo); +% ( $branch, $aba ) = split('\.',$aba) +% if $echeck_country eq 'CA'; +% } % % #false laziness w/view/cust_main/billing.html and misc/payment.cgi % my $routing_label = $echeck_country eq 'US' ? 'ABA/Routing #' @@ -287,7 +289,7 @@ if ( $curr_value ) { } else { $cust_payby = new FS::cust_payby {}; } -my $sel_payby = $cust_payby->payby; +my $sel_payby = $cgi->param($name.'_payby') || $cust_payby->payby; $sel_payby = 'CARD' if $sel_payby eq 'DCRD' || $sel_payby eq ''; $sel_payby = 'CHEK' if $sel_payby eq 'DCHK'; diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index fe59ec5..669f59b 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -317,8 +317,6 @@ tie my %report_ticketing, 'Tie::IxHash', tie my %report_bill_event, 'Tie::IxHash', 'All billing events' => [ $fsurl.'search/report_cust_event.html', 'All billing events for a date range' ], 'Billing event errors' => [ $fsurl.'search/report_cust_event.html?failed=1', 'Failed credit cards, processor or printer problems, etc.' ], -# 'All invoice events' => [ $fsurl.'search/cust_bill_event.html', 'Reports on deprecated, old-style invoice events for a date range' ], -# 'Invoice event errors' => [ $fsurl.'search/cust_bill_event.html?failed=1', 'Reports on deprecated, old-style events for failed credit cards, processor or printer problems, etc.' ], ; tie my %report_payments, 'Tie::IxHash', @@ -668,7 +666,6 @@ $config_billing{'Billing events'} = [ $fsurl.'browse/part_event.html', 'Billing if $curuser->access_right('Edit billing events') || $curuser->access_right('Edit global billing events'); if ( $curuser->access_right('Configuration') ) { - #$config_billing{'Invoice events'} = [ $fsurl.'browse/part_bill_event.cgi', 'Deprecated, old-style actions for overdue invoices' ]; $config_billing{'Invoice configurations'} = [ $fsurl.'browse/invoice_conf.html', 'Adjust invoice settings for special-purpose notices' ]; $config_billing{'Invoice templates'} = [ $fsurl.'browse/invoice_template.html', 'Edit templates for HTML, plaintext and typeset invoices' ]; $config_billing{'separator'} = ''; #its a separator! diff --git a/httemplate/misc/email_invoice_events.cgi b/httemplate/misc/email_invoice_events.cgi deleted file mode 100644 index d65fe17..0000000 --- a/httemplate/misc/email_invoice_events.cgi +++ /dev/null @@ -1,9 +0,0 @@ -<% $server->process %> -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); - -my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reemail', $cgi; - -</%init> diff --git a/httemplate/misc/fax_invoice_events.cgi b/httemplate/misc/fax_invoice_events.cgi deleted file mode 100644 index 05420ee..0000000 --- a/httemplate/misc/fax_invoice_events.cgi +++ /dev/null @@ -1,9 +0,0 @@ -<% $server->process %> -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); - -my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_refax', $cgi; - -</%init> diff --git a/httemplate/misc/print_invoice_events.cgi b/httemplate/misc/print_invoice_events.cgi deleted file mode 100644 index c974d5f..0000000 --- a/httemplate/misc/print_invoice_events.cgi +++ /dev/null @@ -1,9 +0,0 @@ -<% $server->process %> -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); - -my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reprint', $cgi; - -</%init> diff --git a/httemplate/search/cust_bill.html b/httemplate/search/cust_bill.html index bd302c6..0820733 100755 --- a/httemplate/search/cust_bill.html +++ b/httemplate/search/cust_bill.html @@ -119,7 +119,7 @@ if ( $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/ ) { } #arrays - for my $param (qw( cust_classnum payby )) { + for my $param (qw( cust_classnum )) { $search{$param} = [ $cgi->param($param) ] if grep { $_ eq $param } $cgi->param; } diff --git a/httemplate/search/cust_bill_event.cgi b/httemplate/search/cust_bill_event.cgi deleted file mode 100644 index 9fb533a..0000000 --- a/httemplate/search/cust_bill_event.cgi +++ /dev/null @@ -1,167 +0,0 @@ -<& elements/search.html, - 'title' => $title, - 'html_init' => $html_init, - 'menubar' => $menubar, - 'name' => 'billing events', - 'query' => $sql_query, - 'count_query' => $count_sql, - 'header' => [ 'Event', - 'Date', - 'Status', - #'Inv #', 'Inv Date', 'Cust #', - 'Invoice', - FS::UI::Web::cust_header(), - ], - 'fields' => [ - 'event', - sub { time2str("%b %d %Y %T", $_[0]->_date) }, - sub { - #my $cust_bill_event = shift; - my $status = $_[0]->status; - $status .= ': '.$_[0]->statustext - if $_[0]->statustext; - $status; - }, - sub { - #my $cust_bill_event = shift; - 'Invoice #'. $_[0]->invnum. - ' ('. - time2str("%D", $_[0]->cust_bill_date). - ')'; - }, - \&FS::UI::Web::cust_fields, - ], - 'align' => 'lrlr'.FS::UI::Web::cust_aligns(), - 'links' => [ - '', - '', - '', - sub { - my $part_bill_event = shift; - my $template = $part_bill_event->templatename; - $template .= '-' if $template; - [ "${p}view/cust_bill.cgi?$template", 'invnum']; - }, - ( map { $_ ne 'Cust. Status' ? $link_cust : '' } - FS::UI::Web::cust_header() - ), - ], - 'color' => [ - '', - '', - '', - '', - FS::UI::Web::cust_colors(), - ], - 'style' => [ - '', - '', - '', - '', - FS::UI::Web::cust_styles(), - ], - -&> -<%init> - -my $curuser = $FS::CurrentUser::CurrentUser; - -die "access denied" - unless $curuser->access_right('Billing event reports') - or $curuser->access_right('View customer billing events') - && $cgi->param('invnum') =~ /^(\d+)$/; - -my $title = $cgi->param('failed') - ? 'Failed invoice events' - : 'Invoice events'; - -my %search = (); - -if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) { - $search{agentnum} = $1; -} - -($search{beginning}, $search{ending}) - = FS::UI::Web::parse_beginning_ending($cgi); - -if ( $cgi->param('failed') ) { - $search{failed} = '1'; -} - -if ( $cgi->param('part_bill_event.payby') =~ /^(\w+)$/ ) { - $search{payby} = $1; -} - -if ( $cgi->param('invnum') =~ /^(\d+)$/ ) { - $search{invnum} = $1; -} - -my $where = 'WHERE '. FS::cust_bill_event->search_sql_where( \%search ); - -my $join = 'LEFT JOIN part_bill_event USING ( eventpart ) '. - 'LEFT JOIN cust_bill USING ( invnum ) '. - FS::UI::Web::join_cust_main('cust_bill'); - -my $sql_query = { - 'table' => 'cust_bill_event', - 'select' => join(', ', - 'cust_bill_event.*', - 'part_bill_event.event', - 'cust_bill.custnum', - 'cust_bill._date AS cust_bill_date', - 'cust_main.custnum AS cust_main_custnum', - FS::UI::Web::cust_sql_fields(), - ), - 'hashref' => {}, - 'extra_sql' => $where, - 'order_by' => 'ORDER BY _date ASC', - 'addl_from' => $join, -}; - -my $count_sql = "SELECT COUNT(*) FROM cust_bill_event $join $where"; - -my $conf = new FS::Conf; - -my $html_init = ' - <FONT SIZE="+1">Invoice events are the deprecated, old-style actions taken o -n open invoices. See Reports->Billing events->Billing events for current event reports.</FONT><BR><BR>'; - -$html_init .= join("\n", map { - ( my $action = $_ ) =~ s/_$//; - include('/elements/progress-init.html', - $_.'form', - [ keys(%search) ], - "../misc/${_}invoice_events.cgi", - { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but... - $_, #key - ), - qq!<FORM NAME="${_}form">!, - qq!<INPUT TYPE="hidden" NAME="action" VALUE="$_">!, #not used though - (map {qq!<INPUT TYPE="hidden" NAME="$_" VALUE="$search{$_}">!} keys(%search)), - qq!</FORM>! -} qw( print_ email_ fax_ ) ); - -my $menubar = []; - -if ( $curuser->access_right('Resend invoices') ) { - - push @$menubar, 'Re-print these events' => - "javascript:print_process()", - 'Re-email these events' => - "javascript:email_process()", - ; - - push @$menubar, 'Re-fax these events' => - "javascript:fax_process()" - if $conf->exists('hylafax'); - -} - -my $link_cust = sub { - my $cust_bill_event = shift; - $cust_bill_event->cust_main_custnum - ? [ "${p}view/cust_main.cgi?", 'custnum' ] - : ''; -}; - -</%init> diff --git a/httemplate/search/cust_bill_event.html b/httemplate/search/cust_bill_event.html deleted file mode 100755 index 0f84a55..0000000 --- a/httemplate/search/cust_bill_event.html +++ /dev/null @@ -1,67 +0,0 @@ -<% include( - '/elements/header.html', - ( $cgi->param('failed') ? 'Failed invoice events' : 'Invoice events' ), - ) -%> - - <FONT SIZE="+1">Invoice events are the deprecated, old-style actions taken - on open invoices. See Reports->Billing events->Billing events for current event reports.</FONT><BR><BR> - - <FORM ACTION="cust_bill_event.cgi" METHOD="GET"> - <INPUT TYPE="hidden" NAME="failed" VALUE="<% $cgi->param('failed') ? 1 : 0 %>"> - <TABLE> - - <% include( '/elements/tr-select-agent.html', 'disable_empty'=>0 ) %> - - <!--<TR> - <TD ALIGN="right">Customer type</TD> - <TD><SELECT MULTIPLE NAME="perhaps_payby"> - <OPTION SELECTED VALUE="CARD">Credit card (automatic) - <OPTION SELECTED VALUE="CHEK">E-check (automatic) - <OPTION SELECTED VALUE="LECB">Phone bill billing - <OPTION SELECTED VALUE="BILL">Billing - <OPTION SELECTED VALUE="DCRD">Credit card (on-demand) - <OPTION SELECTED VALUE="DCHK">E-check (on-demand) - </TD> - </TR> - --> - <% include( '/elements/tr-input-beginning_ending.html' ) %> - <!-- - <TR> - <TD ALIGN="right">Events: </TD> - <TD> - <SELECT NAME="eventpart"> - <OPTION SELECTED VALUE=""><% $cgi->param('failed') ? '(all failed events)' : '(all events)' %> -% #foreach my $part_bill_event ( qsearch( 'part_bill_event', {} ) ) { -% #} - - </SELECT> - </TD> - </TR> - --> - <TR> - <TD ALIGN="right">Events for payment type: </TD> - <TD> - <SELECT NAME="part_bill_event.payby"> - <OPTION SELECTED VALUE="">(all) - <OPTION VALUE="CARD">Credit card (automatic) - <OPTION VALUE="BILL">Billing - <OPTION VALUE="CHEK">Electronic check (automatic) - <OPTION VALUE="DCRD">Credit card (on-demand) - <OPTION VALUE="DCHK">Electronic check (on-demand) - <OPTION VALUE="LECB">Phone bill billing - <OPTION VALUE="COMP">Complimentary - </SELECT> - </TD> - </TR> - </TABLE> - <BR><INPUT TYPE="submit" VALUE="Get Report"> - </FORM> - -<% include('/elements/footer.html') %> -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Billing event reports'); - -</%init> diff --git a/httemplate/search/cust_bill_void.html b/httemplate/search/cust_bill_void.html index d99f759..38bbf45 100644 --- a/httemplate/search/cust_bill_void.html +++ b/httemplate/search/cust_bill_void.html @@ -124,10 +124,6 @@ if ( grep { $_ eq 'cust_classnum' } $cgi->param ) { if ( $cgi->param('invnum_max') =~ /^\s*(\d+)\s*$/ ) { $search{'invnum_max'} = $1; } - #payby - if ( $cgi->param('payby') ) { - $search{'payby'} = [ $cgi->param('payby') ]; - } #amounts $search{'charged'} = [ FS::UI::Web::parse_lt_gt($cgi, 'charged') ]; diff --git a/httemplate/search/cust_event.html b/httemplate/search/cust_event.html index f1b9951..757982b 100644 --- a/httemplate/search/cust_event.html +++ b/httemplate/search/cust_event.html @@ -163,7 +163,7 @@ for my $param (@scalars) { } #lists -my @lists = qw( payby eventpart ); +my @lists = qw( eventpart ); foreach my $param (@lists) { $search{$param} = [ $cgi->param($param) ]; } diff --git a/httemplate/search/cust_tax_exempt.cgi b/httemplate/search/cust_tax_exempt.cgi index 005d77c..91b2001 100644 --- a/httemplate/search/cust_tax_exempt.cgi +++ b/httemplate/search/cust_tax_exempt.cgi @@ -61,7 +61,6 @@ my @where = (); #if ( $beginning || $ending ) { # push @where, "_date >= $beginning", # "_date <= $ending"; -# #"payby != 'COMP'; #} if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { diff --git a/httemplate/search/cust_tax_exempt_pkg.cgi b/httemplate/search/cust_tax_exempt_pkg.cgi index ba3f275..7b4a6d0 100644 --- a/httemplate/search/cust_tax_exempt_pkg.cgi +++ b/httemplate/search/cust_tax_exempt_pkg.cgi @@ -107,7 +107,6 @@ my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); if ( $beginning || $ending ) { push @where, "_date >= $beginning", "_date <= $ending"; - #"payby != 'COMP'; } if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { diff --git a/httemplate/search/report_cust_bill.html b/httemplate/search/report_cust_bill.html index 8734467..3efe830 100644 --- a/httemplate/search/report_cust_bill.html +++ b/httemplate/search/report_cust_bill.html @@ -33,17 +33,6 @@ 'all_selected' => 1, &> -% if ( $cust_main ) { - <INPUT TYPE="hidden" NAME="payby" VALUE="<% $cust_main->payby %>"> -% } else { - <& /elements/tr-select-payby.html, - label => emt('Payment method:'), - payby_type => 'cust', - multiple => 1, - all_selected => 1, - &> -% } - </TABLE> <BR> diff --git a/httemplate/search/report_cust_bill_pkg.html b/httemplate/search/report_cust_bill_pkg.html index e1b45ec..9dc8b16 100644 --- a/httemplate/search/report_cust_bill_pkg.html +++ b/httemplate/search/report_cust_bill_pkg.html @@ -32,15 +32,6 @@ &> --> -<!-- customer payment method i guess - <& /elements/tr-select-payby.html, - label => emt('Payment method:'), - payby_type => 'cust', - multiple => 1, - all_selected => 1, - &> ---> - <TR> <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="nottax" VALUE="Y" onClick="nottax_changed(this)" onChange="nottax_change(thid)"></TD> <TD><% mt('Omit taxes') |h %></TD> diff --git a/httemplate/search/report_cust_bill_void.html b/httemplate/search/report_cust_bill_void.html index cb13b78..91209ae 100644 --- a/httemplate/search/report_cust_bill_void.html +++ b/httemplate/search/report_cust_bill_void.html @@ -28,17 +28,6 @@ 'all_selected' => 1, &> -% if ( $cust_main ) { - <INPUT TYPE="hidden" NAME="payby" VALUE="<% $cust_main->payby %>"> -% } else { - <& /elements/tr-select-payby.html, - label => emt('Payment method:'), - payby_type => 'cust', - multiple => 1, - all_selected => 1, - &> -% } - </TABLE> <BR> diff --git a/httemplate/search/report_cust_credit_bill_pkg.html b/httemplate/search/report_cust_credit_bill_pkg.html index 1754032..ad0f3f6 100644 --- a/httemplate/search/report_cust_credit_bill_pkg.html +++ b/httemplate/search/report_cust_credit_bill_pkg.html @@ -41,15 +41,6 @@ field => 'amount', &> -<!-- customer payment method i guess - <& /elements/tr-select-payby.html, - label => emt('Payment method:'), - payby_type => 'cust', - multiple => 1, - all_selected => 1, - &> ---> - <!-- <TR> <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="nottax" VALUE="Y" onClick="nottax_changed(this)" onChange="nottax_change(thid)"></TD> diff --git a/httemplate/search/report_cust_credit_source_bill_pkg.html b/httemplate/search/report_cust_credit_source_bill_pkg.html index 05f21c0..b579b92 100644 --- a/httemplate/search/report_cust_credit_source_bill_pkg.html +++ b/httemplate/search/report_cust_credit_source_bill_pkg.html @@ -44,15 +44,6 @@ &> --> -<!-- customer payment method in a 4.x world? huh. how's that work? - <& /elements/tr-select-payby.html, - label => emt('Payment method:'), - payby_type => 'cust', - multiple => 1, - all_selected => 1, - &> ---> - </TABLE> <BR> diff --git a/httemplate/search/report_cust_event.html b/httemplate/search/report_cust_event.html index e0d6242..0dd98d4 100644 --- a/httemplate/search/report_cust_event.html +++ b/httemplate/search/report_cust_event.html @@ -19,14 +19,6 @@ ) %> - <% include( '/elements/tr-select-payby.html', - 'label' => 'Customer payment type', - 'payby_type' => 'cust', - 'multiple' => 1, - 'all_selected' => 1, - ) - %> - <% include( '/elements/tr-select-part_event.html', 'label' => 'Events', 'multiple' => 1, diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi index 27376d5..6bc499a 100755 --- a/httemplate/view/cust_bill.cgi +++ b/httemplate/view/cust_bill.cgi @@ -111,10 +111,6 @@ <A HREF="<%$p%>search/cust_event.html?invnum=<% $cust_bill->invnum %>">( <% mt('View invoice events') |h %> )</A> % } -% if ( $cust_bill->num_cust_bill_event ) { $br++; -<A HREF="<%$p%>search/cust_bill_event.cgi?invnum=<% $cust_bill->invnum %>">( <% mt('View deprecated, old-style invoice events') |h %> )</A> -% } - % my @modes = grep {! $_->disabled} % $cust_bill->cust_main->agent->invoice_modes; % if ( @modes ) { @@ -178,8 +174,7 @@ my %opt = ( $opt{'barcode_img'} = 1 if $conf->exists('invoice-barcode'); my @payby = grep /\w/, $conf->config('payby'); -#@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP )) -@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP )) +@payby = (qw( CARD DCRD CHEK DCHK BILL CASH )) unless @payby; my %payby = map { $_=>1 } @payby; diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index f1125c0..4f4b745 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -13,8 +13,18 @@ &> % } +% my $yes = emt('yes'); +% my $no = emt('no'); + <TABLE CLASS="fsinnerbox"> +% if ( $cust_main->complimentary ) { + <TR> + <TD ALIGN="right"><% mt('Complimentary') |h %></TD> + <TD BGCOLOR="#ffffff"><% $yes %></TD> + </TR> +% } + %( my $balance = $cust_main->balance ) % =~ s/^(\-?)(.*)$/<FONT SIZE=+1>$1<\/FONT>$money_char$2/; @@ -53,9 +63,6 @@ </TR> % } -% my $yes = emt('yes'); -% my $no = emt('no'); - % my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); % unless ( $conf->exists('cust_class-tax_exempt') diff --git a/httemplate/view/cust_statement.html b/httemplate/view/cust_statement.html index 5d37b31..87a185f 100755 --- a/httemplate/view/cust_statement.html +++ b/httemplate/view/cust_statement.html @@ -55,12 +55,6 @@ my $statementnum = $3; my $conf = new FS::Conf; -my @payby = grep /\w/, $conf->config('payby'); -#@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP )) -@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP )) - unless @payby; -my %payby = map { $_=>1 } @payby; - my $cust_statement = qsearchs({ 'select' => 'cust_statement.*', 'table' => 'cust_statement', diff --git a/rt/share/html/Elements/CalendarSlotSchedule b/rt/share/html/Elements/CalendarSlotSchedule index 55c45cd..ff3e634 100644 --- a/rt/share/html/Elements/CalendarSlotSchedule +++ b/rt/share/html/Elements/CalendarSlotSchedule @@ -83,7 +83,8 @@ % "&Owner=$username". % '&Starts='. $Date->strftime('%F').'%20'. $Starts. % '&Due='. $Date->strftime('%F').'%20'. $Due. -% '&new-MemberOf='. $member; #XXX uri_escape? +% '&new-MemberOf='. $member. #XXX uri_escape? +% '&Status=new'; % #'&Requestors='. #XXX Freeside customer requestor(s) (package? onmouseover = "boxon(this);" |