From: Ivan Kohler Date: Tue, 3 Nov 2015 17:00:21 +0000 (-0800) Subject: Merge branch 'master' of git.freeside.biz:/home/git/freeside X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=a87e91ee19d14a6fc3da62f4b44a9628d32bb6a3;hp=4fdc6b443f4f9f51f0879cc19b2fe8c5ef1dac14 Merge branch 'master' of git.freeside.biz:/home/git/freeside --- diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 89c70f75c..f272cd490 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -2521,8 +2521,8 @@ sub _do_bop_realtime { #this used to apply a credit, but now we can void invoices... foreach my $cust_bill (@cust_bill) { - my $voiderror = $cust_bill->void(); - warn "Error voiding cust bill after decline: $voiderror"; + my $voiderror = $cust_bill->void('automatic payment failed'); + warn "Error voiding cust bill after decline: $voiderror" if $voiderror; } } diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index bc69a5f79..5d719c490 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -830,8 +830,8 @@ sub new_customer { #this used to apply a credit, but now we can void invoices... foreach my $cust_bill (@cust_bill) { - my $voiderror = $cust_bill->void(); - warn "Error voiding cust bill after decline: $voiderror"; + my $voiderror = $cust_bill->void('automatic payment failed'); + warn "Error voiding cust bill after decline: $voiderror" if $voiderror; } #should check list for errors... diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index ffaef9707..e02aa1f87 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -712,6 +712,8 @@ sub print_generic { # "balance_date_range" unfortunately is unsuitable for this, since it # cares about application dates. We want to know the sum of all # _top-level transactions_ dated before the last invoice. + # + # still do this for the "Previous Balance" line of the summary block my @sql = map "$_ WHERE _date <= ? AND custnum = ?", ( "SELECT COALESCE( SUM(charged), 0 ) FROM cust_bill", @@ -744,19 +746,31 @@ sub print_generic { # longer stored in the database) $invoice_data{'true_previous_balance'} = $last_bill_balance; - # the change in balance from immediately after that invoice - # to immediately before this one - my $before_this_bill_balance = 0; + # Now, get all applications of credits/payments dated on or after the + # previous bill, to invoices before the current bill. (The + # credit/payment date restriction prevents these from intersecting + # the "Previous Balance" set.) + # These are "adjustments". The past due balance will be shown as + # Previous Balance - Adjustments. + my $adjustments = 0; + @sql = map { + "SELECT COALESCE(SUM(y.amount),0) FROM $_ JOIN cust_bill USING (invnum) + WHERE cust_bill._date < ? + AND x._date >= ? + AND cust_bill.custnum = ?" + } "cust_credit AS x JOIN cust_credit_bill y USING (crednum)", + "cust_pay AS x JOIN cust_bill_pay y USING (paynum)" + ; foreach (@sql) { my $delta = FS::Record->scalar_sql( $_, - $self->_date - 1, + $self->_date, + $last_bill->_date, $self->custnum, ); - $before_this_bill_balance += $delta; + $adjustments += $delta; } - $invoice_data{'balance_adjustments'} = - sprintf("%.2f", $last_bill_balance - $before_this_bill_balance); + $invoice_data{'balance_adjustments'} = sprintf("%.2f", $adjustments); warn sprintf("BALANCE ADJUSTMENTS: %.2f\n\n", $invoice_data{'balance_adjustments'} diff --git a/FS/FS/cdr/amcom.pm b/FS/FS/cdr/amcom.pm index fee81f7df..697a6827f 100644 --- a/FS/FS/cdr/amcom.pm +++ b/FS/FS/cdr/amcom.pm @@ -2,9 +2,9 @@ package FS::cdr::amcom; use strict; use base qw( FS::cdr ); -use vars qw( %info ); +use vars qw( %info %cdrtypes); use DateTime; -use FS::Record qw( qsearchs ); +use FS::Record qw( qsearch ); use FS::cdr_type; my ($tmp_mday, $tmp_mon, $tmp_year); @@ -16,6 +16,12 @@ my ($tmp_mday, $tmp_mon, $tmp_year); 'type' => 'csv', 'sep_char' => ',', 'disabled' => 0, + 'header_buffer' => sub { + + %cdrtypes = ( map { $_->cdrtypename => $_->cdrtypenum } + qsearch('cdr_type', {}) + ); + }, #listref of what to do with each field from the CDR, in order 'import_fields' => [ @@ -37,9 +43,7 @@ my ($tmp_mday, $tmp_mon, $tmp_year); sub { # 5. Call Category (LOCAL, NATIONAL, FREECALL, MOBILE) my ($cdr, $data) = @_; $data ||= 'none'; - - my $cdr_type = qsearchs('cdr_type', { 'cdrtypename' => $data } ); - $cdr->set('cdrtypenum', $cdr_type->cdrtypenum) if $cdr_type; + $cdr->cdrtypenum($cdrtypes{$data} || ''); $cdr->set('dcontext', $data); }, sub { # 6. Start Date (DDMMYYYY diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 974af6743..376ef0263 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -1205,9 +1205,10 @@ sub smart_search_param { my @or = map { my $table = $_; my $search_sql = "FS::$table"->search_sql($string); + my $addl_from = "FS::$table"->search_sql_addl_from(); "SELECT $table.svcnum AS svcnum, '$table' AS svcdb ". - "FROM $table WHERE $search_sql"; + "FROM $table $addl_from WHERE $search_sql"; } FS::part_svc->svc_tables; diff --git a/FS/FS/log_context.pm b/FS/FS/log_context.pm index bd142471c..ff3471760 100644 --- a/FS/FS/log_context.pm +++ b/FS/FS/log_context.pm @@ -18,6 +18,8 @@ my @contexts = ( qw( queue upgrade upgrade_taxable_billpkgnum + freeside-paymentech-upload + freeside-paymentech-download ) ); =head1 NAME diff --git a/FS/FS/msg_template/InitialData.pm b/FS/FS/msg_template/InitialData.pm index dbb9f4037..baf145d8b 100644 --- a/FS/FS/msg_template/InitialData.pm +++ b/FS/FS/msg_template/InitialData.pm @@ -22,6 +22,23 @@ If you did not request this password reset, you may safely ignore and delete thi END ], }, + { msgname => 'Refund receipt', + msgclass => 'email', + mime_type => 'text/html', + _conf => 'refund_receipt_msgnum', + _insert_args => [ subject => '{ $company_name } refund receipt', + body => <<'END', +Dear {$first} {$last},
+
+The following refund has been applied to your account.
+
+Refund ID: {$refundnum}
+Date: {$date}
+Amount: {$refund}
+ +END + ], + }, ]; } diff --git a/FS/FS/part_pkg/discount_Mixin.pm b/FS/FS/part_pkg/discount_Mixin.pm index dcca3436f..4c8675346 100644 --- a/FS/FS/part_pkg/discount_Mixin.pm +++ b/FS/FS/part_pkg/discount_Mixin.pm @@ -4,6 +4,7 @@ use strict; use vars qw( %info ); use Time::Local qw( timelocal ); use List::Util qw( min ); +use FS::Record qw( qsearchs ); use FS::cust_pkg; use FS::cust_bill_pkg_discount; diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index 355c38342..35415a26f 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -1349,6 +1349,9 @@ sub search_sql { #my( $class, $string ) = @_; '1 = 0'; #false } +sub search_sql_addl_from { + ''; +} =item search HASHREF diff --git a/FS/FS/svc_circuit.pm b/FS/FS/svc_circuit.pm index f705c68f4..408bd79e4 100644 --- a/FS/FS/svc_circuit.pm +++ b/FS/FS/svc_circuit.pm @@ -218,6 +218,20 @@ sub label { $self->get('circuit_id'); } +sub search_sql { + my ($class, $string) = @_; + my @where = (); + push @where, 'LOWER(svc_circuit.circuit_id) = \''.lc($string).'\''; + push @where, 'LOWER(circuit_provider.provider) = \''.lc($string).'\''; + push @where, 'LOWER(circuit_type.typename) = \''.lc($string).'\''; + '(' . join(' OR ', @where) . ')'; +} + +sub search_sql_addl_from { + 'LEFT JOIN circuit_provider USING ( providernum ) '. + 'LEFT JOIN circuit_type USING ( typenum )'; +} + =back =head1 SEE ALSO diff --git a/FS/bin/freeside-paymentech-download b/FS/bin/freeside-paymentech-download index 16ac3c23b..1b2f95175 100755 --- a/FS/bin/freeside-paymentech-download +++ b/FS/bin/freeside-paymentech-download @@ -11,11 +11,20 @@ use FS::Record qw(qsearch qsearchs); use FS::pay_batch; use FS::cust_pay_batch; use FS::Conf; +use FS::Log; use vars qw( $opt_t $opt_v $opt_a ); getopts('vta:'); #$Net::SFTP::Foreign::debug = -1; + +sub log_and_die { + my $message = shift; + my $log = FS::Log->new('freeside-paymenttech-download'); + $log->error($message); + die $message; +} + sub usage { " Usage: freeside-paymentech-download [ -v ] [ -t ] [ -a archivedir ] user\n @@ -25,13 +34,13 @@ my $user = shift or die &usage; adminsuidsetup $user; if ( $opt_a ) { - die "no such directory: $opt_a\n" + log_and_die("no such directory: $opt_a\n") unless -d $opt_a; - die "archive directory $opt_a is not writable by the freeside user\n" + log_and_die("archive directory $opt_a is not writable by the freeside user\n") unless -w $opt_a; } -my $unzip_check = `which unzip` or die "can't find unzip executable\n"; +my $unzip_check = `which unzip` or log_and_die("can't find unzip executable\n"); #my $tmpdir = File::Temp->newdir(); my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere? @@ -39,22 +48,31 @@ my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere? my $conf = new FS::Conf; my @batchconf = $conf->config('batchconfig-paymentech'); # BIN, terminalID, merchantID, username, password -my $username = $batchconf[3] or die "no Paymentech batch username configured\n"; -my $password = $batchconf[4] or die "no Paymentech batch password configured\n"; +my $username = $batchconf[3] or log_and_die("no Paymentech batch username configured\n"); +my $password = $batchconf[4] or log_and_die("no Paymentech batch password configured\n"); my $host = ($opt_t ? 'orbitalbatchvar.paymentech.net' : 'orbitalbatch.paymentech.net'); print STDERR "Connecting to $username\@$host...\n" if $opt_v; -my $sftp = Net::SFTP::Foreign->new( host => $host, - user => $username, - password => $password, - timeout => 30, - ); -die "failed to connect to '$username\@$host'\n(".$sftp->error.")\n" if $sftp->error; +my $sftp; +my $ssh_retry = 25; # number of times to try connection, needs to be >= 1 +my $ssh_retry_wait = 60*5; # seconds to wait between tries +while ($ssh_retry > 0) { + $sftp = Net::SFTP::Foreign->new( host => $host, + user => $username, + password => $password, + timeout => 30, + ); + last unless $sftp->error; + $ssh_retry -= 1; + sleep($ssh_retry_wait) if $ssh_retry > 0; +} + +log_and_die("failed to connect to '$username\@$host'\n(".$sftp->error.")\n") if $sftp->error; my @files = map { $_->{filename} } @{ $sftp->ls('.', wanted => qr/_resp\.zip$/) }; -die "no response files found\n" if !@files; +log_and_die("no response files found\n") if !@files; BATCH: foreach my $filename (@files) { diff --git a/FS/bin/freeside-paymentech-upload b/FS/bin/freeside-paymentech-upload index 609019eb2..a6e6a5d28 100755 --- a/FS/bin/freeside-paymentech-upload +++ b/FS/bin/freeside-paymentech-upload @@ -11,12 +11,20 @@ use FS::Record qw(qsearch qsearchs); use FS::pay_batch; use FS::cust_pay_batch; use FS::Conf; +use FS::Log; use vars qw( $opt_a $opt_t $opt_v $opt_p ); getopts('avtp:'); #$Net::SFTP::Foreign::debug = -1; +sub log_and_die { + my $message = shift; + my $log = FS::Log->new('freeside-paymenttech-upload'); + $log->error($message); + die $message; +} + sub usage { " Usage: freeside-paymentech-upload [ -v ] [ -t ] user batchnum @@ -26,7 +34,7 @@ sub usage { " my $user = shift or die &usage; adminsuidsetup $user; -my $zip_check = `which zip` or die "can't find zip executable\n"; +my $zip_check = `which zip` or log_and_die("can't find zip executable\n"); my @batches; @@ -34,21 +42,21 @@ if($opt_a) { my %criteria = (status => 'O'); $criteria{'payby'} = uc($opt_p) if $opt_p; @batches = qsearch('pay_batch', \%criteria); - die "No open batches found".($opt_p ? " of type '$opt_p'" : '').".\n" + log_and_die("No open batches found".($opt_p ? " of type '$opt_p'" : '').".\n") if !@batches; } else { my $batchnum = shift; - die &usage if !$batchnum; + log_and_die("batchnum not passed\n".&usage) if !$batchnum; @batches = qsearchs('pay_batch', { batchnum => $batchnum } ); - die "Can't find payment batch '$batchnum'\n" if !@batches; + log_and_die("Can't find payment batch '$batchnum'\n") if !@batches; } my $conf = new FS::Conf; my @batchconf = $conf->config('batchconfig-paymentech'); # BIN, terminalID, merchantID, username, password -my $username = $batchconf[3] or die "no Paymentech batch username configured\n"; -my $password = $batchconf[4] or die "no Paymentech batch password configured\n"; +my $username = $batchconf[3] or log_and_die("no Paymentech batch username configured\n"); +my $password = $batchconf[4] or log_and_die("no Paymentech batch password configured\n"); #my $tmpdir = File::Temp->newdir(); my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere? @@ -61,7 +69,7 @@ foreach my $pay_batch (@batches) { print STDERR "Exporting batch $batchnum to $filename...\n" if $opt_v; my $text = $pay_batch->export_batch(format => 'paymentech'); $text =~ s!FILEID!$filename! - or die "couldn't find FILEID tag\n"; + or log_and_die("couldn't find FILEID tag\n"); open OUT, ">$tmpdir/$filename.xml"; print OUT $text; close OUT; @@ -69,7 +77,7 @@ foreach my $pay_batch (@batches) { system('zip', '-P', $password, '-q', '-j', "$tmpdir/$filename.zip", "$tmpdir/$filename.xml"); - die "failed to create zip file\n" if (! -f "$tmpdir/$filename.zip" ); + log_and_die("failed to create zip file\n") if (! -f "$tmpdir/$filename.zip" ); push @filenames, $filename; } @@ -77,17 +85,26 @@ my $host = ($opt_t ? 'orbitalbatchvar.paymentech.net' : 'orbitalbatch.paymentech.net'); print STDERR "Connecting to $username\@$host...\n" if $opt_v; -my $sftp = Net::SFTP::Foreign->new( host => $host, - user => $username, - password => $password, - timeout => 30, - ); -die "failed to connect to '$username\@$host'\n(".$sftp->error.")\n" +my $sftp; +my $ssh_retry = 25; # number of times to try connection, needs to be >= 1 +my $ssh_retry_wait = 60*5; # seconds to wait between tries +while ($ssh_retry > 0) { + $sftp = Net::SFTP::Foreign->new( host => $host, + user => $username, + password => $password, + timeout => 30, + ); + last unless $sftp->error; + $ssh_retry -= 1; + sleep($ssh_retry_wait) if $ssh_retry > 0; +} + +log_and_die("failed to connect to '$username\@$host'\n(".$sftp->error.")\n") if $sftp->error; foreach my $filename (@filenames) { $sftp->put("$tmpdir/$filename.zip", "$filename.zip") - or die "failed to upload file (".$sftp->error.")\n"; + or log_and_die("failed to upload file (".$sftp->error.")\n"); } print STDERR "Finished!\n" if $opt_v; diff --git a/httemplate/elements/standardize_locations.js b/httemplate/elements/standardize_locations.js index 1a01daa6f..b824fb249 100644 --- a/httemplate/elements/standardize_locations.js +++ b/httemplate/elements/standardize_locations.js @@ -129,7 +129,7 @@ function confirm_standardize(arg) { function() { overlib( OLresponseAJAX, CAPTION, 'Address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, - 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', + 650, HEIGHT, 368, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); }, 0); @@ -141,10 +141,15 @@ function replace_address() { var newaddr = returned['new']; var cf = document.<% $formname %>; + var crf = document.forms['confirm_replace_form']; % foreach my $pre (@prefixes) { var clean = newaddr['<% $pre %>addr_clean'] == 'Y'; + var replace = true; // auto_standardize_address won't load the form, so just do it + if ( crf && crf['<% $pre %>replace'] ) { + replace = crf['<% $pre %>replace'].value == 'Y'; + } var error = newaddr['<% $pre %>error']; - if ( clean ) { + if ( clean && replace ) { % foreach my $field (qw(address1 address2 state zip addr_clean ),($conf->exists('cust_main-no_city_in_address') ? () : 'city')) { cf.elements['<% $pre %><% $field %>'].value = newaddr['<% $pre %><% $field %>']; % } #foreach $field @@ -154,7 +159,12 @@ function replace_address() { cf.elements['<% $pre %>longitude'].value = newaddr['<% $pre %>longitude']; } % if ( $withcensus ) { - if ( clean && newaddr['<% $pre %>censustract'] ) { + var census_replace = true; + if ( crf && crf['census_replace'] ) { + census_replace = crf['census_replace'].value == 'Y'; + } + + if ( clean && census_replace && newaddr['<% $pre %>censustract'] ) { cf.elements['<% $pre %>censustract'].value = newaddr['<% $pre %>censustract']; } % } #if $withcensus diff --git a/httemplate/elements/tr-cust_svc.html b/httemplate/elements/tr-cust_svc.html index 03de3ba69..2d1a9e6a5 100644 --- a/httemplate/elements/tr-cust_svc.html +++ b/httemplate/elements/tr-cust_svc.html @@ -38,6 +38,10 @@ Usage: <% FS::UI::Web::svc_label_link($m, $part_svc, $cust_svc) %> % } +% if ($part_svc->svcdb eq 'svc_circuit') { +
Provider: <% $svc_x->circuit_provider->provider %> +
Type: <% $svc_x->circuit_type->typename %> +% } % if ( $opt{after_svc_callback} ) { <% &{ $opt{after_svc_callback} }( $cust_svc ) %> % } diff --git a/httemplate/misc/confirm-address_standardize.html b/httemplate/misc/confirm-address_standardize.html index 2eae011c4..0a05c70bd 100644 --- a/httemplate/misc/confirm-address_standardize.html +++ b/httemplate/misc/confirm-address_standardize.html @@ -1,8 +1,15 @@

-% if ( $new{bill_error} or $new{ship_error} ) { +% if ( $is_error ) { Address standardization error % } % else { @@ -10,24 +17,26 @@ Confirm address standardization % }

+
-% my @prefixes = (''); -% if ( $old{same} ) { -% @prefixes = ('bill_'); -% } elsif ( $old{billship} ) { -% @prefixes = ('bill_', 'ship_'); -% } % for my $pre (@prefixes) { % my $name = $pre eq 'bill_' ? 'billing' : 'service'; +% my $rows = 5; % if ( $new{$pre.'error'} ) { - + + + + -% if ( $old{$pre.'company'} ) { +% if ( $old{$pre.'company'} ) { - % } + @@ -39,9 +48,16 @@ Confirm address standardization % } else { # not an error +% $rows++ if !$new{$pre.'addr_clean'}; + + % if ( !$new{$pre.'addr_clean'} ) { @@ -75,11 +91,16 @@ Confirm address standardization %# only do this part if address standardization provided a censustract % my $pre = $old{same} ? 'bill_' : 'ship_'; % my $censustract = $new{$pre.'censustract'}; -% my $census_error = $new{$pre.'census_error'}; % if ( $censustract ) { + + @@ -93,35 +114,21 @@ Confirm address standardization % } #if censustract -% if ( grep {$new{$_.'error'}} @prefixes ) { + + -% } else { - - - - -
Entered <%$name%> address CLASS="td_radio"> + + Entered <%$name%> address +
<% $old{$pre.'company'} %>
<% $old{$pre.'address1'} %> <% $new{$pre.'error'} %><% $old{$pre.'city'} %>, <% $old{$pre.'state'} %> <% $old{$pre.'zip'} %>
CLASS="td_radio"> + + Entered <%$name%> address Standardized <%$name%> address CLASS="td_radio"> + +
+ > + Entered census tract Calculated census tract + > +
<% $old{$pre.'censustract'} %>
-
- -
- -
-% } # !error +
<%init> # slightly weird interface... @@ -132,4 +139,14 @@ my %new = %{ $q->{new} }; my $addresses = $old{billship} ? 'addresses' : 'address'; +my @prefixes = (''); +if ( $old{same} ) { + @prefixes = ('bill_'); +} elsif ( $old{billship} ) { + @prefixes = ('bill_', 'ship_'); +} + +my $census_error = $new{'census_error'}; +my $is_error = $census_error || grep { $new{$_.'error'} } @prefixes; + diff --git a/httemplate/search/report_tax-xls.cgi b/httemplate/search/report_tax-xls.cgi index 9b02457b0..07fcf7cfe 100755 --- a/httemplate/search/report_tax-xls.cgi +++ b/httemplate/search/report_tax-xls.cgi @@ -207,11 +207,11 @@ foreach my $row (@rows) { $x++; $ws->write_string($y, $x, " \N{U+2212} ", $f->{bigmath}); # MINUS SIGN $x++; - $ws->write($y, $x, $row->{credit} || 0, $f->{currency}); + $ws->write($y, $x, $row->{tax_credited} || 0, $f->{currency}); $x++; $ws->write_string($y, $x, " = ", $f->{bigmath}); $x++; - $ws->write($y, $x, $row->{tax} - $row->{credit}, $f->{currency}); + $ws->write($y, $x, $row->{tax} - $row->{tax_credited}, $f->{currency}); $x++; $ws->write($y, $x, $row->{tax_paid} || 0, $f->{currency});