summaryrefslogtreecommitdiff
path: root/httemplate
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate')
-rw-r--r--httemplate/browse/discount.html30
-rw-r--r--httemplate/edit/agent_payment_gateway.html7
-rw-r--r--httemplate/edit/cust_main/name.html20
-rw-r--r--httemplate/edit/cust_main/stateid.html7
-rwxr-xr-xhttemplate/edit/cust_refund.cgi73
-rwxr-xr-xhttemplate/edit/process/cust_refund.cgi46
-rw-r--r--httemplate/elements/cust_payby_new.html222
-rw-r--r--httemplate/elements/link-replace_element_text.html45
-rw-r--r--httemplate/elements/tr-select-cust_payby.html2
-rw-r--r--httemplate/elements/tr-select-router_block_ip.html128
-rw-r--r--httemplate/misc/download-batch.cgi11
-rw-r--r--httemplate/misc/payment.cgi183
-rw-r--r--httemplate/misc/process/payment.cgi7
-rw-r--r--httemplate/misc/xmlhttp-free_addresses_in_block.json.html18
-rw-r--r--httemplate/search/e911.html156
-rw-r--r--httemplate/search/prospect_main.html1
-rw-r--r--httemplate/view/cust_main/contacts.html37
-rw-r--r--httemplate/view/cust_main/menu.html2
-rw-r--r--httemplate/view/prospect_main.html17
19 files changed, 707 insertions, 305 deletions
diff --git a/httemplate/browse/discount.html b/httemplate/browse/discount.html
index 9b2298ae4..deb98c3c7 100644
--- a/httemplate/browse/discount.html
+++ b/httemplate/browse/discount.html
@@ -1,22 +1,18 @@
<% include( 'elements/browse.html',
'title' => 'Discounts',
'name' => 'discounts',
- 'menubar' => [ 'Add a new discount' =>
- $p.'edit/discount.html',
- ],
- 'query' => { 'table' => 'discount', },
+ 'menubar' => \@menubar,
+ 'query' => \%query,
+ 'order_by_sql' => { description => 'discountnum' },
'count_query' => 'SELECT COUNT(*) FROM discount',
'disableable' => 1,
'disabled_statuspos' => 1,
- 'header' => [ 'Name', 'Comment', 'Class', 'Discount', ],
+ 'header' => [ 'Name', 'Class', 'Discount', ],
'fields' => [ 'name',
- 'comment',
'classname',
'description',
],
- 'links' => [ $link,
- $link,
- ],
+ 'links' => \@links
)
%>
<%init>
@@ -24,6 +20,20 @@
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
-my $link = [ "${p}edit/discount.html?", 'discountnum' ];
+my @links = (
+ [ "${p}edit/discount.html?", 'discountnum' ],
+ [ "${p}edit/discount_class.html?", 'classnum' ],
+);
+
+my %query = (
+ select => 'discount.*, discount_class.*',
+ table => 'discount',
+ addl_from => 'LEFT JOIN discount_class USING(classnum)',
+);
+
+my @menubar = (
+ 'Add a new discount' => $p.'edit/discount.html',
+ 'Discount classes' => $p.'browse/discount_class.html',
+);
</%init>
diff --git a/httemplate/edit/agent_payment_gateway.html b/httemplate/edit/agent_payment_gateway.html
index 6d15164ac..38411f12e 100644
--- a/httemplate/edit/agent_payment_gateway.html
+++ b/httemplate/edit/agent_payment_gateway.html
@@ -18,9 +18,12 @@ Use gateway <SELECT NAME="gatewaynum">
<OPTION VALUE="<% $payment_gateway->gatewaynum %>"><% $payment_gateway->gateway_module %> (<% $payment_gateway->gateway_username %>)
% }
-
</SELECT>
-<BR><BR>
+<BR>
+
+<INPUT TYPE="checkbox" NAME="cardtype" VALUE="ACH"> for ACH only.
+<BR>
+<BR>
<INPUT TYPE="submit" VALUE="Add gateway override">
</FORM>
diff --git a/httemplate/edit/cust_main/name.html b/httemplate/edit/cust_main/name.html
index 713f54cdb..120475b92 100644
--- a/httemplate/edit/cust_main/name.html
+++ b/httemplate/edit/cust_main/name.html
@@ -1,7 +1,18 @@
<%def .namepart>
-% my ($field, $value, $label, $extra) = @_;
+% my ($field, $value, $label, $extra, $unmask_field) = @_;
<DIV STYLE="display: inline-block" ID="<% $field %>_input">
<INPUT TYPE="text" NAME="<% $field %>" VALUE="<% $value |h %>" <%$extra%>>
+% if (
+% $value
+% && ref $unmask_field
+% && !$unmask_field->{unmask_ss}
+% && $FS::CurrentUser::CurrentUser->access_right( $unmask_field->{access_right} )
+% ) {
+ <& /elements/link-replace_element_text.html, {
+ target_id => $unmask_field->{target_id},
+ replace_text => $unmask_field->{replace_text},
+ } &>
+% }
<BR><FONT SIZE="-1" COLOR="#333333"><% emt($label) %></FONT>
</DIV>
</%def>
@@ -13,7 +24,12 @@
<& .namepart, 'first', $cust_main->first, 'First' &>
% if ( $conf->exists('show_ss') ) {
&nbsp;
- <& .namepart, 'ss', $ss, 'SS#', "SIZE=11" &>
+ <& .namepart, 'ss', $ss, 'SS#', "SIZE=11 ID='ss'", {
+ target_id => 'ss',
+ replace_text => $cust_main->ss,
+ access_right => 'Unmask customer SSN',
+ unmask_ss => $conf->exists('unmask_ss'),
+ } &>
% } else {
<INPUT TYPE="hidden" NAME="ss" VALUE="<% $ss %>">
% }
diff --git a/httemplate/edit/cust_main/stateid.html b/httemplate/edit/cust_main/stateid.html
index 3500d631c..0f288099b 100644
--- a/httemplate/edit/cust_main/stateid.html
+++ b/httemplate/edit/cust_main/stateid.html
@@ -1,7 +1,12 @@
% if ( $conf->exists('show_stateid') ) {
<TR>
<TH ALIGN="right"><% $stateid_label %></TH>
- <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>" SIZE=12></TD>
+ <TD>
+ <INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>" SIZE=12 ID="stateid">
+% if ( $stateid && $FS::CurrentUser::CurrentUser->access_right( 'Unmask customer DL' )) {
+ <& /elements/link-replace_element_text.html, {target_id => 'stateid', replace_text => $cust_main->stateid} &>
+% }
+ </TD>
<TD><& /elements/select-state.html,
state => $cust_main->stateid_state,
country => $cust_main->country, # how does this work on new customer?
diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi
index e1975ed70..f3dec98e1 100755
--- a/httemplate/edit/cust_refund.cgi
+++ b/httemplate/edit/cust_refund.cgi
@@ -34,7 +34,7 @@
% }
<BR>Payment
- <% ntable("#cccccc", 2) %>
+ <TABLE class="fsinnerbox">
<TR>
<TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">$<% $cust_pay->paid %></TD>
@@ -85,7 +85,8 @@
<BR>Refund
-<% ntable("#cccccc", 2) %>
+
+<TABLE class="fsinnerbox">
<TR>
<TD ALIGN="right">Date</TD>
@@ -102,9 +103,23 @@
<TD ALIGN="right">Check #</TD>
<TD COLSPAN=2><INPUT TYPE="text" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10></TD>
</TR>
+ </TABLE>
% }
-% elsif ($payby eq 'CHEK') {
+% elsif ($payby eq 'CHEK' || $payby eq 'CARD') {
%
+<SCRIPT TYPE="text/javascript">
+ function cust_payby_changed (what) {
+ var custpaybynum = what.options[what.selectedIndex].value
+ if ( custpaybynum == '' || custpaybynum == '0' ) {
+ //what.form.payinfo.disabled = false;
+ $('#cust_payby').slideDown();
+ } else {
+ //what.form.payinfo.value = '';
+ //what.form.payinfo.disabled = true;
+ $('#cust_payby').slideUp();
+ }
+ }
+</SCRIPT>
% my @cust_payby = ();
% if ( $payby eq 'CARD' ) {
% @cust_payby = $cust_main->cust_payby('CARD','DCRD');
@@ -117,16 +132,58 @@
% my $custpaybynum = length(scalar($cgi->param('custpaybynum')))
% ? scalar($cgi->param('custpaybynum'))
% : scalar(@cust_payby) && $cust_payby[0]->custpaybynum;
-<& /elements/tr-select-cust_payby.html,
+
+% if ($cust_pay) {
+ <INPUT TYPE="hidden" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10>
+% }
+% else {
+ <& /elements/tr-select-cust_payby.html,
'cust_payby' => \@cust_payby,
'curr_value' => $custpaybynum,
'onchange' => 'cust_payby_changed(this)',
-&>
- <INPUT TYPE="hidden" NAME="batch" VALUE="1">
+ &>
+% }
+
+% if ( $conf->exists("batch-enable")
+% || grep $payby eq $_, $conf->config('batch-enable_payby')
+% ) {
+% if ( grep $payby eq $_, $conf->config('realtime-disable_payby') ) {
+ <INPUT TYPE="hidden" NAME="batch" VALUE="1">
+% } else {
+ <TR>
+ <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="batch" VALUE="1" ID="batch" <% ($batchnum || $batch) ? 'checked' : '' %> ></TD>
+ <TH ALIGN="left">&nbsp;&nbsp;&nbsp;<% mt('Add to current batch') |h %></TH>
+ </TR>
+% }
+% }
+
+ </TABLE>
+<P>
+
+% if ( !$cust_pay ) {
+<DIV ID="cust_payby"
+ <% $custpaybynum ? 'STYLE="display:none"'
+ : ''
+ %>
+>
+<TABLE class="fsinnerbox">
+
+ <& /elements/cust_payby_new.html,
+ 'cust_payby' => \@cust_payby,
+ 'curr_value' => $custpaybynum,
+ &>
+
+</TABLE>
+</DIV>
+% } # end if cust_pay
+
% } else {
<INPUT TYPE="hidden" NAME="payinfo" VALUE="">
+ </TABLE>
% }
+<P>
+<TABLE class="fsinnerbox">
<& /elements/tr-select-reason.html,
'field' => 'reasonnum',
'reason_class' => 'F',
@@ -159,16 +216,18 @@ my $payby = $cgi->param('payby');
my $payinfo = $cgi->param('payinfo');
my $reason = $cgi->param('reason');
my $link = $cgi->param('popup') ? 'popup' : '';
+my $batch = $cgi->param('batch');
die "access denied"
unless $FS::CurrentUser::CurrentUser->refund_access_right($payby);
-my( $paynum, $cust_pay ) = ( '', '' );
+my( $paynum, $cust_pay, $batchnum ) = ( '', '', '' );
if ( $cgi->param('paynum') =~ /^(\d+)$/ ) {
$paynum = $1;
$cust_pay = qsearchs('cust_pay', { paynum=>$paynum } )
or die "unknown payment # $paynum";
$refund ||= $cust_pay->unrefunded;
+ $batchnum = $cust_pay->batchnum;
if ( $custnum ) {
die "payment # $paynum is not for specified customer # $custnum"
unless $custnum == $cust_pay->custnum;
diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi
index 0a3d55036..1f96456e0 100755
--- a/httemplate/edit/process/cust_refund.cgi
+++ b/httemplate/edit/process/cust_refund.cgi
@@ -53,7 +53,7 @@ if ( $error ) {
'CHEK' => 'electronic check (ACH)',
);
-my( $cust_payby, $payinfo, $paycvv, $month, $year, $payname );
+my( $cust_pay, $cust_payby, $payinfo, $paycvv, $month, $year, $payname );
my $paymask = '';
if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
@@ -71,6 +71,18 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
$paycvv = $cust_payby->paycvv; # pass it if we got it, running a transaction will clear it
( $month, $year ) = $cust_payby->paydate_mon_year;
$payname = $cust_payby->payname;
+ $cgi->param(-name=>"paytype", -value=>$cust_payby->paytype) unless $cgi->param("paytype");
+
+} elsif ( $cgi->param('paynum') > 0) {
+
+ $cust_pay = qsearchs({
+ 'table' => 'cust_pay',
+ 'hashref' => { 'paynum' => $cgi->param('paynum') },
+ 'select' => 'cust_pay.*, cust_pay_batch.payname ',
+ 'addl_from' => "left join cust_pay_batch on cust_pay_batch.batchnum = cust_pay.batchnum and cust_pay_batch.custnum = $custnum ",
+ });
+ $payinfo = $cust_pay->payinfo;
+ $payname = $cust_pay->payname;
} else {
@@ -192,16 +204,19 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
my $refund = "$1$2";
$cgi->param('paynum') =~ /^(\d*)$/ or die "Illegal paynum!";
my $paynum = $1;
- my $paydate = $cgi->param('exp_year'). '-'. $cgi->param('exp_month'). '-01';
- $options{'paydate'} = $paydate if $paydate =~ /^\d{2,4}-\d{1,2}-01$/;
+ my $paydate;
+ unless ($paynum) {
+ if ($cust_payby->paydate) { $paydate = "$year-$month-01"; }
+ else { $paydate = "2037-12-01"; }
+ }
if ( $cgi->param('batch') ) {
-
+ $paydate = "2037-12-01" unless $paydate;
$error ||= $cust_main->batch_card(
'payby' => $payby,
'amount' => $refund,
'payinfo' => $payinfo,
- 'paydate' => "$year-$month-01",
+ 'paydate' => $paydate,
'payname' => $payname,
'paycode' => 'C',
map { $_ => scalar($cgi->param($_)) }
@@ -209,28 +224,23 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
);
errorpage($error) if $error;
-#### post refund #####
my %hash = map {
$_, scalar($cgi->param($_))
} fields('cust_refund');
- $paynum = $cgi->param('paynum');
- $paynum =~ /^(\d*)$/ or die "Illegal paynum!";
- if ($paynum) {
- my $cust_pay = qsearchs('cust_pay',{ 'paynum' => $paynum });
- die "Could not find paynum $paynum" unless $cust_pay;
- $error = $cust_pay->refund(\%hash);
- } else {
- my $new = new FS::cust_refund ( \%hash );
- $error = $new->insert;
- }
- # if not a batch refund run realtime.
+
+ my $new = new FS::cust_refund ( { 'paynum' => $paynum,
+ %hash,
+ } );
+ $error = $new->insert;
+
+ # if not a batch refund run realtime.
} else {
$error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund,
'paynum' => $paynum,
'reasonnum' => scalar($cgi->param('reasonnum')),
%options );
}
-} else {
+} else { # run cash refund.
my %hash = map {
$_, scalar($cgi->param($_))
} fields('cust_refund');
diff --git a/httemplate/elements/cust_payby_new.html b/httemplate/elements/cust_payby_new.html
new file mode 100644
index 000000000..7ed049686
--- /dev/null
+++ b/httemplate/elements/cust_payby_new.html
@@ -0,0 +1,222 @@
+% my $auto = 0;
+% if ( $payby eq 'CARD' ) {
+%
+% my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' );
+% my $payname = $cust_main->first. ' '. $cust_main->getfield('last');
+% my $location = $cust_main->bill_location;
+
+ <TR>
+ <TH ALIGN="right"><% mt('Card number') |h %></TH>
+ <TD COLSPAN=7>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%$payinfo%>"> </TD>
+ <TH><% mt('Exp.') |h %></TH>
+ <TD>
+ <SELECT NAME="month">
+% for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) {
+
+ <OPTION<% $_ == $month ? ' SELECTED' : '' %>><% $_ %>
+% }
+
+ </SELECT>
+ </TD>
+ <TD> / </TD>
+ <TD>
+ <SELECT NAME="year">
+% my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) {
+
+ <OPTION<% $_ == $year ? ' SELECTED' : '' %>><% $_ %>
+% }
+
+ </SELECT>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+ <TR>
+ <TH ALIGN="right"><% mt('CVV2') |h %></TH>
+ <TD><INPUT TYPE="text" NAME="paycvv" VALUE="<% $paycvv %>" SIZE=4 MAXLENGTH=4>
+ (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
+ </TD>
+ </TR>
+ <TR>
+ <TH ALIGN="right"><% mt('Exact name on card') |h %></TH>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%$payname%>"></TD>
+ </TR>
+
+ <& /elements/location.html,
+ 'object' => $location,
+ 'no_asterisks' => 1,
+ 'address1_label' => emt('Card billing address'),
+ &>
+
+% } elsif ( $payby eq 'CHEK' ) {
+%
+% my( $account, $aba, $branch, $payname, $ss, $paytype, $paystate,
+% $stateid, $stateid_state )
+% = ( '', '', '', '', '', '', '', '', '' );
+%
+% #false laziness w/{edit,view}/cust_main/billing.html
+% my $routing_label = $conf->config('echeck-country') eq 'US'
+% ? 'ABA/Routing number'
+% : 'Routing number';
+% my $routing_size = $conf->config('echeck-country') eq 'CA' ? 4 : 10;
+% my $routing_maxlength = $conf->config('echeck-country') eq 'CA' ? 3 : 9;
+
+ <INPUT TYPE="hidden" NAME="month" VALUE="12">
+ <INPUT TYPE="hidden" NAME="year" VALUE="2037">
+ <TR>
+ <TD ALIGN="right"><% mt('Account number') |h %></TD>
+ <TD><INPUT TYPE="text" SIZE=10 NAME="payinfo1" VALUE="<%$account%>"></TD>
+ <TD ALIGN="right"><% mt('Type') |h %></TD>
+ <TD><SELECT NAME="paytype"><% join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } FS::cust_payby->paytypes) %></SELECT></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right"><% mt($routing_label) |h %></TD>
+ <TD>
+ <INPUT TYPE="text" SIZE="<% $routing_size %>" MAXLENGTH="<% $routing_maxlength %>" NAME="payinfo2" VALUE="<%$aba%>">
+ (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
+ </TD>
+ </TR>
+% if ( $conf->config('echeck-country') eq 'CA' ) {
+ <TR>
+ <TD ALIGN="right"><% mt('Branch number') |h %></TD>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo3" VALUE="<%$branch%>" SIZE=6 MAXLENGTH=5>
+ </TD>
+ </TR>
+% }
+ <TR>
+ <TD ALIGN="right"><% mt('Bank name') |h %></TD>
+ <TD><INPUT TYPE="text" NAME="payname" VALUE="<%$payname%>"></TD>
+ </TR>
+
+% if ( $conf->exists('show_bankstate') ) {
+ <TR>
+ <TD ALIGN="right"><% mt('Bank state') |h %></TD>
+ <TD><& /elements/select-state.html,
+ 'disable_empty' => 0,
+ 'empty_label' => emt('(choose)'),
+ 'state' => $paystate,
+ 'country' => $cust_main->country,
+ 'prefix' => 'pay',
+ &>
+ </TD>
+ </TR>
+% } else {
+ <INPUT TYPE="hidden" NAME="paystate" VALUE="<% $paystate %>">
+% }
+
+% if ( $conf->exists('show_ss') ) {
+ <TR>
+ <TD ALIGN="right">
+ <% mt('Account holder') |h %><BR>
+ <% mt('Social security or tax ID #') |h %>
+ </TD>
+ <TD><INPUT TYPE="text" NAME="ss" VALUE="<% $ss %>"></TD>
+ </TR>
+% } else {
+ <INPUT TYPE="hidden" NAME="ss" VALUE="<% $ss %>"></TD>
+% }
+
+% if ( $conf->exists('show_stateid') ) {
+ <TR>
+ <TD ALIGN="right">
+ <% mt('Account holder') |h %><BR>
+ <% mt("Driver's license or state ID #") |h %>
+ </TD>
+ <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>"></TD>
+ <TD ALIGN="right"><% mt('State') |h %></TD>
+ <TD><& /elements/select-state.html,
+ 'disable_empty' => 0,
+ 'empty_label' => emt('(choose)'),
+ 'state' => $stateid_state,
+ 'country' => $cust_main->country,
+ 'prefix' => 'stateid_',
+ &>
+ </TD>
+ </TR>
+% } else {
+ <INPUT TYPE="hidden" NAME="stateid" VALUE="<% $stateid %>">
+ <INPUT TYPE="hidden" NAME="stateid_state" VALUE="<% $stateid_state %>">
+% }
+
+% } #end CARD/CHEK-specific section
+
+
+<TR>
+ <TD COLSPAN=8>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ <% mt('Remember this information') |h %>
+ </TD>
+</TR>
+
+<TR>
+ <TD COLSPAN=8>
+ <INPUT TYPE="checkbox"<% $auto ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ <% mt("Charge future payments to this [_1] automatically",$type{$payby}) |h %>
+% if ( @cust_payby ) {
+ <% mt('as') |h %>
+ <SELECT NAME="weight">
+% for ( 1 .. 1+scalar(grep { $_->payby =~ /^(CARD|CHEK)$/ } @cust_payby) ) {
+ <OPTION VALUE="<%$_%>"><% mt( $weight{$_} ) |h %>
+% }
+ </SELECT>
+% } else {
+ <INPUT TYPE="hidden" NAME="weight" VALUE="1">
+% }
+ </TD>
+</TR>
+
+<%once>
+
+my %weight = (
+ 1 => 'Primary',
+ 2 => 'Secondary',
+ 3 => 'Tertiary',
+ 4 => 'Fourth',
+ 5 => 'Fifth',
+ 6 => 'Sixth',
+ 7 => 'Seventh',
+);
+
+</%once>
+
+<%init>
+
+my %opt = @_;
+
+my @cust_payby = @{$opt{cust_payby}};
+
+my %type = ( 'CARD' => 'credit card',
+ 'CHEK' => 'electronic check (ACH)',
+ );
+
+$cgi->param('payby') =~ /^(CARD|CHEK)$/
+ or die "unknown payby ". $cgi->param('payby');
+my $payby = $1;
+
+$cgi->param('custnum') =~ /^(\d+)$/
+ or die "illegal custnum ". $cgi->param('custnum');
+my $custnum = $1;
+
+my $cust_main = qsearchs( 'cust_main', { 'custnum'=>$custnum } );
+die "unknown custnum $custnum" unless $cust_main;
+
+my $balance = $cust_main->balance;
+
+my $payinfo = '';
+
+my $conf = new FS::Conf;
+
+#false laziness w/selfservice make_payment.html shortcut for one-country
+my %states = map { $_->state => 1 }
+ qsearch('cust_main_county', {
+ 'country' => $conf->config('countrydefault') || 'US'
+ } );
+my @states = sort { $a cmp $b } keys %states;
+
+</%init> \ No newline at end of file
diff --git a/httemplate/elements/link-replace_element_text.html b/httemplate/elements/link-replace_element_text.html
new file mode 100644
index 000000000..8e611954c
--- /dev/null
+++ b/httemplate/elements/link-replace_element_text.html
@@ -0,0 +1,45 @@
+<%doc>
+
+Display a link with javascript to replace text within a element.
+
+Usage:
+
+<& /elements/link-replace_element_text.html, {
+ target_id => 'input_id',
+ replace_text => 'hello',
+
+ element_type => 'input', # Uses jquery val() method to replace text
+ element_type => 'div', # Uses jquery text() method to replace text
+
+ href => ...
+ style => ...
+ class => ...
+ }
+&>
+
+</%doc>
+<a href="<% $param{href} %>"
+ style="<% $param{style} %>"
+% if ($param{class}) {
+ class="<% $param{class} %>"
+% }
+ onClick="$('#<% $param{target_id} %>').<% $param{jmethod} %>('<% $param{replace_text} |h %>');">&#x25C1;</a>
+<%init>
+
+die "template call requires a parameter hashref" unless ref $_[0];
+
+# Defaults that can be overridden in param hashref
+my %param = (
+ target_id => 'SPECIFY_AN_INPUT_ELEMENT_ID',
+ replace_text => 'REPLACEMENT_TEXT_FOR_INPUT_ELEMENT',
+ element_type => 'input',
+
+ link_text => '%#x25C1;', # ◁
+ href => 'javascript:void(0)',
+ style => 'text-decoration:none;',
+ class => undef,
+
+ %{ $_[0] },
+);
+$param{jmethod} = $param{element_type} eq 'input' ? 'val' : 'text';
+</%init>
diff --git a/httemplate/elements/tr-select-cust_payby.html b/httemplate/elements/tr-select-cust_payby.html
index e2b2e09d1..e5ace4d39 100644
--- a/httemplate/elements/tr-select-cust_payby.html
+++ b/httemplate/elements/tr-select-cust_payby.html
@@ -1,4 +1,4 @@
-% if ( scalar(@{ $opt{'cust_payby'} }) == 0 ) {
+% if ( scalar(@{ $opt{'cust_payby'} }) == 0 ) {
<INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'custpaybynum' %>" VALUE="">
diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html
index 2aa715e29..72640d3d5 100644
--- a/httemplate/elements/tr-select-router_block_ip.html
+++ b/httemplate/elements/tr-select-router_block_ip.html
@@ -2,34 +2,110 @@
var manual_addr_routernum = <% encode_json(\%manual_addr_routernum) %>;
var ip_addr_curr_value = <% $opt{'ip_addr'} |js_string %>;
var blocknum_curr_value = <% $opt{'blocknum'} |js_string %>;
-function update_ip_addr(obj, i) {
- var routernum = document.getElementById('router_select_0').value;
- var select_blocknum = document.getElementById('router_select_1');
- var blocknum = select_blocknum.value;
- var input_ip_addr = document.getElementById('input_ip_addr');
+
+function update_ip_addr() {
+ var routernum = $('#router_select_0').val() || "";
+ var blocknum = $('#router_select_1').val() || "";
+ var e_input_ip_addr = $('#input_ip_addr');
+ var e_router_select_1 = $('#router_select_1');
+
+ <% # Is block is automatically selected for this router? %>
if ( manual_addr_routernum[routernum] == 'Y' ) {
-%# hide block selection and default ip address to its previous value
- select_blocknum.style.display = 'none';
- input_ip_addr.value = ip_addr_curr_value;
- }
- else {
-%# the reverse
- select_blocknum.style.display = '';
-%# default ip address to null, unless the router/block are set to the
-%# previous value, in which case default it to current value
+ show_ip_input();
+ hide_ip_select();
+ e_router_select_1.hide();
+ e_input_ip_addr.val( ip_addr_curr_value );
+ } else {
+ e_router_select_1.show();
+ e_input_ip_addr.attr('placeholder', <% mt('(automatic)') | js_string %> );
if ( routernum == router_curr_values[0] &&
- blocknum == router_curr_values[1] ) {
- input_ip_addr.value = ip_addr_curr_value;
+ blocknum == router_curr_values[1] ) {
+ e_input_ip_addr.val( ip_addr_curr_value );
} else {
- input_ip_addr.value = <% mt('(automatic)') |js_string %>;
+ e_input_ip_addr.val('');
}
}
+ show_or_hide_toggle_ip();
+ populate_ip_select();
+}
+
+function toggle_ip_input() {
+ if ( $('#input_ip_addr').is(':hidden') ) {
+ show_ip_input();
+ } else {
+ show_ip_select();
+ }
+}
+
+function show_ip_input() {
+ $('#input_ip_addr').show();
+ $('#select_ip_addr').hide();
+ depopulate_ip_select();
+}
+
+function show_ip_select() {
+ var e_input_ip_addr = $('#input_ip_addr');
+ var e_select_ip_addr = $('#select_ip_addr');
+
+ e_select_ip_addr.width( e_input_ip_addr.width() );
+ e_input_ip_addr.hide();
+ e_select_ip_addr.show();
+ populate_ip_select();
+}
+
+function populate_ip_select() {
+ depopulate_ip_select();
+ var e = $('#select_ip_addr');
+ var blocknum = $('#router_select_1').val();
+
+ var opts = [ '<option value="">loading...</option>' ];
+ e.html(opts.join(''));
+
+% if ( $opt{ip_addr} ) {
+ opts = [
+ '<option value="<% $opt{ip_addr} |h %>"><% $opt{ip_addr} |h %></option>',
+ '<option value="">-----------</option>'
+ ];
+% } else {
+ opts = [ '<option value=""><% mt('(automatic)') |h %></option>' ];
+% }
+ if ( blocknum && $.isNumeric(blocknum) && ! e.is(':hidden')) {
+ $.getJSON(
+ '<% $p %>misc/xmlhttp-free_addresses_in_block.json.html',
+ {blocknum: blocknum},
+ function(ip_json) {
+ $.each( ip_json, function(idx, val) {
+ opts.push(
+ '<option' + (val == ip_addr_curr_value ? 'selected' : '') + '>'
+ + val
+ + '</option>'
+ );
+ });
+ e.html(opts.join(''));
+ }
+ );
+ }
}
-function clearhint_ip_addr (what) {
- if ( what.value == <% mt('(automatic)') |js_string %> )
- what.value = '';
+
+function depopulate_ip_select() {
+ $('#select_ip_addr').children().remove();
}
+
+function propogate_ip_select() {
+ $('#input_ip_addr').val( $('#select_ip_addr').val() );
+}
+
+function show_or_hide_toggle_ip() {
+ if ( $('#router_select_1').val() ) {
+ $('#toggle_ip').show();
+ } else {
+ show_ip_input();
+ $('#toggle_ip').hide();
+ }
+}
+
</script>
+
<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router'), required => $opt{'required'} &>
<td>
<& /elements/select-tiered.html, prefix => 'router_', tiers => [
@@ -58,14 +134,20 @@ function clearhint_ip_addr (what) {
</td></tr>
<& /elements/tr-td-label.html, label => ($opt{'ip_addr_label'} || 'IP address'), required => $opt{'ip_addr_required'} &>
<td>
-% #warn Dumper \%fixed;
% if ( exists $fixed{$ip_field} ) {
<input type="hidden" id="input_ip_addr" name="<% $ip_field %>"
value="<% $opt{'ip_addr'} |h%>"><% $opt{'ip_addr'} || '' %>
% }
% else {
- <input type="text" id="input_ip_addr" name="<% $ip_field %>"
- value="<% $opt{'ip_addr'} |h%>" onfocus="clearhint_ip_addr(this)">
+ <input type="text"
+ id="input_ip_addr"
+ name="<% $ip_field %>"
+ value="<% $opt{'ip_addr'} | h %>"
+ onfocus="clearhint_ip_addr(this)">
+ <select id="select_ip_addr" style="display: none;" onChange='javascript:propogate_ip_select();'>
+ <option><% mt('loading') |h %>...</option>
+ </select>
+ <button type="button" onClick='javascript:toggle_ip_input();' id="toggle_ip" style="display: none;">&#9660;</button>
% }
</td> </tr>
<script type="text/javascript">
diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi
index c4bc37e93..c6a0b68c3 100644
--- a/httemplate/misc/download-batch.cgi
+++ b/httemplate/misc/download-batch.cgi
@@ -20,9 +20,18 @@ elsif ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) {
$opt{'format'} = $1;
}
-my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } );
+my $credit_transactions = "EXISTS (SELECT 1 FROM cust_pay_batch WHERE batchnum = $batchnum AND paycode = 'C') AS arecredits";
+my $pay_batch = qsearchs({ 'select' => "*, $credit_transactions",
+ 'table' => 'pay_batch',
+ 'hashref' => { batchnum => $batchnum },
+ });
die "Batch not found: '$batchnum'" if !$pay_batch;
+if ($pay_batch->{Hash}->{arecredits}) {
+ my $export_format = "FS::pay_batch::".$opt{'format'};
+ die "This format can not handle refunds." unless $export_format->can('can_handle_credits');
+}
+
my $exporttext = $pay_batch->export_batch(%opt);
unless ($exporttext) {
http_header('Content-Type' => 'text/html' );
diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi
index 4f6f7ef75..80cb15d79 100644
--- a/httemplate/misc/payment.cgi
+++ b/httemplate/misc/payment.cgi
@@ -135,178 +135,10 @@ function change_batch_checkbox () {
>
<TABLE class="fsinnerbox">
-% my $auto = 0;
-% if ( $payby eq 'CARD' ) {
-%
-% my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' );
-% my $payname = $cust_main->first. ' '. $cust_main->getfield('last');
-% my $location = $cust_main->bill_location;
-
- <TR>
- <TH ALIGN="right"><% mt('Card number') |h %></TH>
- <TD COLSPAN=7>
- <TABLE>
- <TR>
- <TD>
- <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%$payinfo%>"> </TD>
- <TH><% mt('Exp.') |h %></TH>
- <TD>
- <SELECT NAME="month">
-% for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) {
-
- <OPTION<% $_ == $month ? ' SELECTED' : '' %>><% $_ %>
-% }
-
- </SELECT>
- </TD>
- <TD> / </TD>
- <TD>
- <SELECT NAME="year">
-% my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) {
-
- <OPTION<% $_ == $year ? ' SELECTED' : '' %>><% $_ %>
-% }
-
- </SELECT>
- </TD>
- </TR>
- </TABLE>
- </TD>
- </TR>
- <TR>
- <TH ALIGN="right"><% mt('CVV2') |h %></TH>
- <TD><INPUT TYPE="text" NAME="paycvv" VALUE="<% $paycvv %>" SIZE=4 MAXLENGTH=4>
- (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
- </TD>
- </TR>
- <TR>
- <TH ALIGN="right"><% mt('Exact name on card') |h %></TH>
- <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%$payname%>"></TD>
- </TR>
-
- <& /elements/location.html,
- 'object' => $location,
- 'no_asterisks' => 1,
- 'address1_label' => emt('Card billing address'),
- &>
-
-% } elsif ( $payby eq 'CHEK' ) {
-%
-% my( $account, $aba, $branch, $payname, $ss, $paytype, $paystate,
-% $stateid, $stateid_state )
-% = ( '', '', '', '', '', '', '', '', '' );
-%
-% #false laziness w/{edit,view}/cust_main/billing.html
-% my $routing_label = $conf->config('echeck-country') eq 'US'
-% ? 'ABA/Routing number'
-% : 'Routing number';
-% my $routing_size = $conf->config('echeck-country') eq 'CA' ? 4 : 10;
-% my $routing_maxlength = $conf->config('echeck-country') eq 'CA' ? 3 : 9;
-
- <INPUT TYPE="hidden" NAME="month" VALUE="12">
- <INPUT TYPE="hidden" NAME="year" VALUE="2037">
- <TR>
- <TD ALIGN="right"><% mt('Account number') |h %></TD>
- <TD><INPUT TYPE="text" SIZE=10 NAME="payinfo1" VALUE="<%$account%>"></TD>
- <TD ALIGN="right"><% mt('Type') |h %></TD>
- <TD><SELECT NAME="paytype"><% join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } FS::cust_payby->paytypes) %></SELECT></TD>
- </TR>
- <TR>
- <TD ALIGN="right"><% mt($routing_label) |h %></TD>
- <TD>
- <INPUT TYPE="text" SIZE="<% $routing_size %>" MAXLENGTH="<% $routing_maxlength %>" NAME="payinfo2" VALUE="<%$aba%>">
- (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
- </TD>
- </TR>
-% if ( $conf->config('echeck-country') eq 'CA' ) {
- <TR>
- <TD ALIGN="right"><% mt('Branch number') |h %></TD>
- <TD>
- <INPUT TYPE="text" NAME="payinfo3" VALUE="<%$branch%>" SIZE=6 MAXLENGTH=5>
- </TD>
- </TR>
-% }
- <TR>
- <TD ALIGN="right"><% mt('Bank name') |h %></TD>
- <TD><INPUT TYPE="text" NAME="payname" VALUE="<%$payname%>"></TD>
- </TR>
-
-% if ( $conf->exists('show_bankstate') ) {
- <TR>
- <TD ALIGN="right"><% mt('Bank state') |h %></TD>
- <TD><& /elements/select-state.html,
- 'disable_empty' => 0,
- 'empty_label' => emt('(choose)'),
- 'state' => $paystate,
- 'country' => $cust_main->country,
- 'prefix' => 'pay',
- &>
- </TD>
- </TR>
-% } else {
- <INPUT TYPE="hidden" NAME="paystate" VALUE="<% $paystate %>">
-% }
-
-% if ( $conf->exists('show_ss') ) {
- <TR>
- <TD ALIGN="right">
- <% mt('Account holder') |h %><BR>
- <% mt('Social security or tax ID #') |h %>
- </TD>
- <TD><INPUT TYPE="text" NAME="ss" VALUE="<% $ss %>"></TD>
- </TR>
-% } else {
- <INPUT TYPE="hidden" NAME="ss" VALUE="<% $ss %>"></TD>
-% }
-
-% if ( $conf->exists('show_stateid') ) {
- <TR>
- <TD ALIGN="right">
- <% mt('Account holder') |h %><BR>
- <% mt("Driver's license or state ID #") |h %>
- </TD>
- <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>"></TD>
- <TD ALIGN="right"><% mt('State') |h %></TD>
- <TD><& /elements/select-state.html,
- 'disable_empty' => 0,
- 'empty_label' => emt('(choose)'),
- 'state' => $stateid_state,
- 'country' => $cust_main->country,
- 'prefix' => 'stateid_',
- &>
- </TD>
- </TR>
-% } else {
- <INPUT TYPE="hidden" NAME="stateid" VALUE="<% $stateid %>">
- <INPUT TYPE="hidden" NAME="stateid_state" VALUE="<% $stateid_state %>">
-% }
-
-% } #end CARD/CHEK-specific section
-
-
-<TR>
- <TD COLSPAN=8>
- <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
- <% mt('Remember this information') |h %>
- </TD>
-</TR>
-
-<TR>
- <TD COLSPAN=8>
- <INPUT TYPE="checkbox"<% $auto ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
- <% mt("Charge future payments to this [_1] automatically",$type{$payby}) |h %>
-% if ( @cust_payby ) {
- <% mt('as') |h %>
- <SELECT NAME="weight">
-% for ( 1 .. 1+scalar(grep { $_->payby =~ /^(CARD|CHEK)$/ } @cust_payby) ) {
- <OPTION VALUE="<%$_%>"><% mt( $weight{$_} ) |h %>
-% }
- </SELECT>
-% } else {
- <INPUT TYPE="hidden" NAME="weight" VALUE="1">
-% }
- </TD>
-</TR>
+<& /elements/cust_payby_new.html,
+ 'cust_payby' => \@cust_payby,
+ 'curr_value' => $custpaybynum,
+&>
</TABLE>
</DIV>
@@ -355,13 +187,6 @@ my $payinfo = '';
my $conf = new FS::Conf;
-#false laziness w/selfservice make_payment.html shortcut for one-country
-my %states = map { $_->state => 1 }
- qsearch('cust_main_county', {
- 'country' => $conf->config('countrydefault') || 'US'
- } );
-my @states = sort { $a cmp $b } keys %states;
-
my $payunique = "webui-payment-". time. "-$$-". rand() * 2**32;
</%init>
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
index 717d57c85..5620b5b4b 100644
--- a/httemplate/misc/process/payment.cgi
+++ b/httemplate/misc/process/payment.cgi
@@ -90,6 +90,7 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
$paycvv = $cust_payby->paycvv; # pass it if we got it, running a transaction will clear it
( $month, $year ) = $cust_payby->paydate_mon_year;
$payname = $cust_payby->payname;
+ $cgi->param(-name=>"paytype", -value=>$cust_payby->paytype) unless $cgi->param("paytype");
} else {
@@ -208,6 +209,10 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
my $error = '';
my $paynum = '';
+my $paydate;
+if ($cust_payby->paydate) { $paydate = "$year-$month-01"; }
+else { $paydate = "2037-12-01"; }
+
if ( $cgi->param('batch') ) {
$error = 'Prepayment discounts not supported with batched payments'
@@ -217,7 +222,7 @@ if ( $cgi->param('batch') ) {
'payby' => $payby,
'amount' => $amount,
'payinfo' => $payinfo,
- 'paydate' => "$year-$month-01",
+ 'paydate' => $paydate,
'payname' => $payname,
map { $_ => scalar($cgi->param($_)) }
@{$payby2fields{$payby}}
diff --git a/httemplate/misc/xmlhttp-free_addresses_in_block.json.html b/httemplate/misc/xmlhttp-free_addresses_in_block.json.html
new file mode 100644
index 000000000..801718d35
--- /dev/null
+++ b/httemplate/misc/xmlhttp-free_addresses_in_block.json.html
@@ -0,0 +1,18 @@
+<%doc>
+ Return a json array containing all free ip addresses within a given block
+ Unless block is larger than /24 - Does somebody really want to populate
+ 65k addresses into a HTML selectbox?
+</%doc>
+<% encode_json($json) %>\
+<%init>
+
+my $json = [];
+
+my $blocknum = $cgi->param('blocknum');
+
+my $addr_block = qsearchs( addr_block => { blocknum => $blocknum });
+
+$json = $addr_block->free_addrs
+ if ref $addr_block && $addr_block->ip_netmask >= 24;
+
+</%init>
diff --git a/httemplate/search/e911.html b/httemplate/search/e911.html
index 75dbef7d5..6d387d563 100644
--- a/httemplate/search/e911.html
+++ b/httemplate/search/e911.html
@@ -1,6 +1,23 @@
+<%doc>
+
+ E911 Fee Report
+
+ Finds billing totals for a given pkgpart where the bill item matches
+ cust_pkg.pkgpart or cust_bill_pkg.pkgpart_override columns.
+
+ Given date range, filter by when the invoice was paid.
+
+ * E911 access lines - SUM(cust_bill_pkg.quantity)
+ * Total fees charged - SUM(cust_bill_pay_pkg.amount)
+ * Fee payments collected - SUM(cust_bill_pkg.setup) + SUM(cust_bill_pkg.recur)
+
+ * Administrative fee (1%) - 1% of Fee Payments Collected
+ * Amount due - 99% of Fee Payments Collected
+
+</%doc>
% if ( $row ) {
-%# pretty minimal report
<& /elements/header.html, 'E911 Fee Report' &>
+
<& /elements/table-grid.html &>
<STYLE TYPE="text/css">
table.grid TD:first-child { font-weight: normal }
@@ -8,27 +25,27 @@ table.grid TD { font-weight: bold;
text-align: right;
padding: 1px 2px }
</STYLE>
+
<TR><TH COLSPAN=2><% $legend %></TH></TR>
<TR>
- <TD>E911 access lines:</TD>
- <TD><% $row->{quantity} || 0 %></TD>
+ <TD><% mt('E911 access lines') %>:</TD>
+ <TD><% $report{e911_access_lines} %></TD>
</TR>
<TR>
- <TD>Total fees charged: </TD>
- <TD><% $money_char.sprintf('%.2f', $row->{charged_amount}) %></TD>
+ <TD><% mt('Total fees charged') %>: </TD>
+ <TD><% $money_char.$report{fees_charged} %></TD>
</TD>
<TR>
- <TD>Fee payments collected: </TD>
- <TD><% $money_char.sprintf('%.2f', $row->{paid_amount}) %></TD>
+ <TD><% mt('Fee payments collected') %>: </TD>
+ <TD><% $money_char.$report{fees_collected} %></TD>
</TR>
<TR>
- <TD>Administrative fee (1%): </TD>
- <TD><% $money_char.sprintf('%.2f', $row->{paid_amount} * $admin_fee) %></TD>
+ <TD><% mt('Administrative fee') %> (1%): </TD>
+ <TD><% $money_char.$report{admin_fee} %></TD>
</TR>
<TR>
- <TD>Amount due: </TD>
- <TD><% $money_char.sprintf('%.2f', $row->{paid_amount} * (1-$admin_fee) ) %>
- </TD>
+ <TD><% mt('Amount due') %>: </TD>
+ <TD><% $money_char.$report{e911_amount_due} %></TD>
</TR>
</TABLE>
<& /elements/footer.html &>
@@ -38,6 +55,8 @@ table.grid TD { font-weight: bold;
% }
<%init>
+our $DEBUG;
+
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
@@ -56,56 +75,89 @@ my $agentnum = $1;
# package classes, etc.), do NOT simply loop through this and do a
# bazillion scalar_sql queries. Use a properly grouped aggregate query.
-my $select = 'SELECT cust_bill_pkg.billpkgnum, cust_bill_pkg.quantity, '.
-'cust_bill_pkg.setup, SUM(cust_bill_pay_pkg.amount) AS paid_amount';
-
-my $from = 'FROM cust_pkg
- JOIN cust_bill_pkg USING (pkgnum)
- JOIN cust_bill USING (invnum)
- LEFT JOIN cust_bill_pay_pkg USING (billpkgnum)
- LEFT JOIN cust_bill_pay USING (billpaynum)
-';
-# going by payment application date here, which should be
-# max(invoice date, payment date)
-my $where = "WHERE cust_pkg.pkgpart = $pkgpart
-AND ( (cust_bill_pay._date >= $begin AND cust_bill_pay._date < $end)
- OR cust_bill_pay.paynum IS NULL )";
+my $sql_statement = "
+ SELECT
+ sum(cust_bill_pkg.quantity) as quantity,
+ sum(cust_bill_pay_pkg.amount) as amount,
+ sum(cust_bill_pkg.setup) as setup,
+ sum(cust_bill_pkg.recur) as recur
+ FROM cust_pkg
+ LEFT JOIN cust_bill_pkg USING (pkgnum)
+ LEFT JOIN cust_bill_pay_pkg USING (billpkgnum)
+ LEFT JOIN cust_bill_pay USING (billpaynum)
+";
if ( $agentnum ) {
- $from .= ' JOIN cust_main ON (cust_pkg.custnum = cust_main.custnum)';
- $where .= "\n AND cust_main.agentnum = $agentnum";
+ $sql_statement .= "
+ LEFT JOIN cust_main USING (custnum)
+ WHERE
+ cust_main.agentnum = ?
+ AND ";
+} else {
+ $sql_statement .= "
+ WHERE
+ "
}
+$sql_statement .= "
+ ( cust_bill_pkg.pkgpart_override = ? OR cust_pkg.pkgpart = ? )
+ AND (
+ ( cust_bill_pay._date >= ? AND cust_bill_pay._date < ? )
+ OR cust_bill_pay.paynum IS NULL
+ );
+";
+
+# Preserving this oddball, unexplained epoch substitution
+$end = '' if $end == 4294967295;
-my $subquery = "$select $from $where
-GROUP BY cust_bill_pkg.billpkgnum, cust_bill_pkg.quantity";
-# This has one row for each E911 line item that has any payments applied.
-# Fields are the billpkgnum of the item (currently unused), the number of
-# E911 charges, and the total amount paid (always > 0).
+my @bind_values = (
+ $agentnum ? $agentnum : (),
+ $pkgpart,
+ $pkgpart,
+ $begin || 0,
+ $end || time(),
+);
-# now sum those rows.
-my $sql = "SELECT SUM(quantity) AS quantity, SUM(setup) AS charged_amount,
-SUM(paid_amount) AS paid_amount FROM ($subquery) AS paid_fees"; # no grouping
+if ( $DEBUG ) {
+ warn "\$sql_statement: $sql_statement\n";
+ warn "\@bind_values: ".join(', ',@bind_values)."\n";
+}
-my $sth = dbh->prepare($sql);
-$sth->execute;
+my $sth = dbh->prepare( $sql_statement );
+$sth->execute( @bind_values ) || die $sth->errstr;
my $row = $sth->fetchrow_hashref;
-my $admin_fee = 0.01; # 1% admin fee, allowed in Texas
+my %report = (
+ e911_access_lines => $row->{quantity} || 0,
-$end = '' if $end == 4294967295;
-my $legend = '';
-if ( $agentnum ) {
- $legend = FS::agent->by_key($agentnum)->agent . ', ';
-}
-if ( $begin and $end ) {
- $legend .= time2str('%h %o %Y', $begin) . '&mdash;' .
- time2str('%h %o %Y', $end);
+ fees_charged => sprintf(
+ "%.2f",
+ ( $row->{setup} + $row->{recur} ) || 0,
+ ),
+
+ fees_collected => sprintf(
+ "%.2f",
+ ( $row->{amount} || 0 ),
+ ),
+);
+
+# Does everybody use this 1% admin fee? Should this be configurable?
+$report{admin_fee} = sprintf( "%.2f", $report{fees_collected} * 0.01 );
+$report{e911_amount_due} = $report{fees_collected} - $report{admin_fee};
+
+my $begin_text =
+ $begin
+ ? DateTime->from_epoch(epoch => $begin)->mdy('/')
+ : mt('Anytime');
+
+my $end_text = DateTime->from_epoch(epoch => ( $end || time ))->mdy('/');
+
+my $legend = FS::agent->by_key($agentnum)->agent . ', ' if $agentnum;
+if ( $begin && $end ) {
+ $legend .= "$begin_text &#x2194; $end_text";
} elsif ( $begin ) {
- $legend .= time2str('after %h %o %Y', $begin);
-} elsif ( $end ) {
- $legend .= time2str('before %h %o %Y', $end);
+ $legend .= mt('After')." $begin_text";
} else {
- $legend .= 'any time';
+ $legend .= mt('Through')." $end_text"
}
-$legend = ucfirst($legend);
+
</%init>
diff --git a/httemplate/search/prospect_main.html b/httemplate/search/prospect_main.html
index d65d4d19d..0eb45f338 100644
--- a/httemplate/search/prospect_main.html
+++ b/httemplate/search/prospect_main.html
@@ -17,7 +17,6 @@
}
$pm->prospect_contact
];
- ''
},
sub {
my $pr = shift->part_referral;
diff --git a/httemplate/view/cust_main/contacts.html b/httemplate/view/cust_main/contacts.html
index 1660c1c22..11efcd568 100644
--- a/httemplate/view/cust_main/contacts.html
+++ b/httemplate/view/cust_main/contacts.html
@@ -29,9 +29,24 @@
<TD COLSPAN=5><% $cust_main->contact |h %></TD>
% if ( $conf->exists('show_ss') ) {
<TH ALIGN="right"><% mt('SS#') |h %></TH>
- <TD><% $conf->exists('unmask_ss')
- ? $cust_main->ss
- : $cust_main->masked('ss') || '&nbsp;' %></TD>
+ <TD>
+ <span id="ss_span" style="white-space:nowrap;">
+ <% $conf->exists('unmask_ss')
+ ? $cust_main->ss
+ : $cust_main->masked('ss') || '&nbsp;' %>
+% if (
+% $cust_main->ss
+% && !$conf->exists('unmask_ss')
+% && $FS::CurrentUser::CurrentUser->access_right('Unmask customer SSN')
+% ) {
+ <& /elements/link-replace_element_text.html, {
+ target_id => 'ss_span',
+ replace_text => $cust_main->ss,
+ element_type => 'span'
+ } &>
+% }
+ </span>
+ </TD>
% }
</TR>
% if ( $conf->exists('cust_main-enable_spouse') and
@@ -172,7 +187,21 @@
<TR>
<TH ALIGN="right"><% $stateid_label %></TH>
- <TD><% $cust_main->masked('stateid') || '&nbsp' %></TD>
+ <TD>
+ <span id="stateid_span" style="white-space:nowrap;">
+ <% $cust_main->masked('stateid') || '&nbsp' %>
+% if (
+% $cust_main->stateid
+% && $FS::CurrentUser::CurrentUser->access_right('Unmask customer DL')
+% ) {
+ <& /elements/link-replace_element_text.html, {
+ target_id => 'stateid_span',
+ replace_text => $cust_main->stateid,
+ element_type => 'span'
+ } &>
+% }
+ </span>
+ </TD>
<TH ALIGN="right"><% $stateid_state_label %></TH>
<TD><% $cust_main->stateid_state || '&nbsp' %></TD>
</TR>
diff --git a/httemplate/view/cust_main/menu.html b/httemplate/view/cust_main/menu.html
index f3aca21e8..7ec4d07db 100644
--- a/httemplate/view/cust_main/menu.html
+++ b/httemplate/view/cust_main/menu.html
@@ -460,7 +460,7 @@ my @menu = (
## condition => sub { $payby{MCHK} },
#},
{
- label => 'Batch Electronic check refund',
+ label => 'Enter electronic check refund',
popup => "edit/cust_refund.cgi?popup=1;payby=CHEK;custnum=$custnum",
actionlabel => 'Enter electronic check refund',
width => 440,
diff --git a/httemplate/view/prospect_main.html b/httemplate/view/prospect_main.html
index f4dd4146f..504a5a8ec 100644
--- a/httemplate/view/prospect_main.html
+++ b/httemplate/view/prospect_main.html
@@ -24,8 +24,21 @@
% foreach my $prospect_contact ( $prospect_main->prospect_contact ) {
% my $contact = $prospect_contact->contact;
<TR>
- <TH ALIGN="right"><% $prospect_contact->contact_classname %> Contact</TD>
- <TD BGCOLOR="#FFFFFF"><% $contact->line %></TD>
+ <TH ALIGN="right" VALIGN="top"><% $prospect_contact->contact_classname %> Contact</TH>
+ <TD BGCOLOR="#FFFFFF">
+ <% $contact->line %><br>
+ <table>
+% for my $row ( $contact->contact_email ) {
+ <tr><th>E-Mail:</th><td><% $row->emailaddress %></td></tr>
+% }
+% for my $row ( $contact->contact_phone ) {
+ <tr><th><% $row->phone_type->typename %>:</th><td><% $row->phonenum_pretty %></td></tr>
+% }
+% if ( $prospect_contact->comment ) {
+ <tr><th>Comment:</th><td><% $prospect_contact->comment %></td></tr>
+% }
+ </table>
+ </TD>
</TR>
%}