summaryrefslogtreecommitdiff
path: root/httemplate/view
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/view')
-rw-r--r--httemplate/view/bill_batch.cgi2
-rw-r--r--httemplate/view/cust_main/billing.html4
-rw-r--r--httemplate/view/cust_main/change_history.html7
-rwxr-xr-xhttemplate/view/cust_main/packages.html37
-rw-r--r--httemplate/view/cust_main/packages/contact.html61
-rw-r--r--httemplate/view/cust_main/packages/location.html14
-rw-r--r--httemplate/view/cust_main/packages/package.html135
-rwxr-xr-xhttemplate/view/cust_main/packages/section.html68
-rw-r--r--httemplate/view/cust_main/packages/status.html146
-rw-r--r--httemplate/view/cust_main/payment_history.html152
-rw-r--r--httemplate/view/cust_main/payment_history/attempted_batch_payment.html13
-rw-r--r--httemplate/view/elements/svc_Common.html23
-rw-r--r--httemplate/view/elements/svc_devices.html159
-rw-r--r--httemplate/view/elements/svc_edit_link.html9
-rw-r--r--httemplate/view/elements/svc_export_status.html10
-rwxr-xr-xhttemplate/view/quotation-pdf.cgi29
-rwxr-xr-xhttemplate/view/svc_acct.cgi14
-rw-r--r--httemplate/view/svc_acct/basics.html26
-rw-r--r--httemplate/view/svc_broadband.cgi47
-rw-r--r--httemplate/view/svc_cert.cgi8
-rw-r--r--httemplate/view/svc_hardware.cgi9
-rw-r--r--httemplate/view/svc_phone.cgi15
22 files changed, 658 insertions, 330 deletions
diff --git a/httemplate/view/bill_batch.cgi b/httemplate/view/bill_batch.cgi
index 7d640395e..55ee4be1c 100644
--- a/httemplate/view/bill_batch.cgi
+++ b/httemplate/view/bill_batch.cgi
@@ -13,7 +13,7 @@
'hashref' => { },
'addl_from' =>
'LEFT JOIN cust_bill USING ( invnum ) '.
- 'LEFT JOIN cust_main USING ( custnum )',
+ FS::UI::Web::join_cust_main('cust_bill'),
'extra_sql' => " WHERE batchnum = $batchnum",
},
'count_query' => "SELECT COUNT(*) FROM cust_bill_batch WHERE batchnum = $batchnum",
diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html
index 5c46803d2..b863a734b 100644
--- a/httemplate/view/cust_main/billing.html
+++ b/httemplate/view/cust_main/billing.html
@@ -247,6 +247,10 @@
<TD ALIGN="right"><% mt('Email address(es)') |h %></TD>
<TD BGCOLOR="#ffffff">
<% join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ) || $no %>
+% if ( $cust_main->message_noemail ) {
+ <BR>
+ <SPAN STYLE="font-size: small"><% emt('(do not send notices)') %></SPAN>
+% }
</TD>
</TR>
% }
diff --git a/httemplate/view/cust_main/change_history.html b/httemplate/view/cust_main/change_history.html
index ea84b8f75..bf32a49f9 100644
--- a/httemplate/view/cust_main/change_history.html
+++ b/httemplate/view/cust_main/change_history.html
@@ -43,10 +43,12 @@ tie my %tables, 'Tie::IxHash',
'svc_external' => 'External service',
'svc_phone' => 'Phone',
'phone_device' => 'Phone device',
+ 'cust_pkg_discount' => 'Discount',
#? it gets provisioned anyway 'phone_avail' => 'Phone',
;
-my $svc_join = 'JOIN cust_svc USING ( svcnum ) JOIN cust_pkg USING ( pkgnum )';
+my $pkg_join = "JOIN cust_pkg USING ( pkgnum )";
+my $svc_join = "JOIN cust_svc USING ( svcnum ) $pkg_join";
my %table_join = (
'svc_acct' => $svc_join,
@@ -58,6 +60,7 @@ my %table_join = (
'svc_external' => $svc_join,
'svc_phone' => $svc_join,
'phone_device' => $svc_join,
+ 'cust_pkg_discount'=> $pkg_join,
);
@@ -104,7 +107,7 @@ my $conf = new FS::Conf;
my $curuser = $FS::CurrentUser::CurrentUser;
-die "access deined"
+die "access denied"
unless $curuser->access_right('View customer history');
# find out the beginning of this customer history, if possible
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 7d7930634..546dd89c3 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -1,3 +1,29 @@
+<STYLE TYPE="text/css">
+td.package {
+ vertical-align: top;
+ border-width: 0;
+ border-style: solid;
+ border-color: #bbbbff;
+}
+table.package {
+ border: none;
+ padding: 0;
+ border-spacing: 0;
+ width: 100%;
+}
+table.usage {
+ border: 1px solid black;
+ margin: auto;
+ width: 60%;
+ border-spacing: 0px;
+}
+.shared > * {
+ background-color: #ffffaa;
+}
+.row0 { background-color: #eeeeee; }
+.row1 { background-color: #ffffff; }
+
+</STYLE>
% my $s = 0;
% if ( $curuser->access_right('Qualify service') ) {
@@ -75,7 +101,7 @@
<TR>
<TD COLSPAN=2>
-% if ( $conf->exists('cust_pkg-group_by_location') and $show_location ) {
+% if ( $conf->exists('cust_pkg-group_by_location') ) {
<& locations.html,
'cust_main' => $cust_main,
'packages' => $packages,
@@ -87,7 +113,6 @@
<& packages/section.html,
'cust_main' => $cust_main,
'packages' => $packages,
- 'show_location' => $show_location,
&>
</TABLE>
% }
@@ -114,10 +139,6 @@ my $curuser = $FS::CurrentUser::CurrentUser;
my( $packages, $num_old_packages ) = get_packages($cust_main, $conf);
-
-my $show_location = $conf->exists('cust_pkg-always_show_location')
- || (grep $_->locationnum, @$packages); # ? '1' : '0';
-
my $countrydefault = scalar($conf->config('countrydefault')) || 'US';
#subroutines
@@ -178,6 +199,10 @@ sub get_packages {
}
$num_old_packages -= scalar(@packages);
+
+ # don't include supplemental packages in this list; they'll be found from
+ # their main packages
+ @packages = grep !$_->main_pkgnum, @packages;
( \@packages, $num_old_packages );
}
diff --git a/httemplate/view/cust_main/packages/contact.html b/httemplate/view/cust_main/packages/contact.html
new file mode 100644
index 000000000..93129915f
--- /dev/null
+++ b/httemplate/view/cust_main/packages/contact.html
@@ -0,0 +1,61 @@
+% if ( $contact ) {
+ <% $contact->line |h %>
+% if ( $show_link ) {
+ <FONT SIZE=-1>
+ (&nbsp;<%pkg_change_contact_link($cust_pkg)%>&nbsp;)
+ </FONT>
+% }
+% } elsif ( $show_link ) {
+ <FONT SIZE=-1>
+ (&nbsp;<%pkg_add_contact_link($cust_pkg)%>&nbsp;)
+ </FONT>
+% }
+<%init>
+
+my $conf = new FS::Conf;
+my %opt = @_;
+
+my $cust_pkg = $opt{'cust_pkg'};
+
+my $show_link =
+ ! $cust_pkg->get('cancel')
+ && $FS::CurrentUser::CurrentUser->access_right('Change customer package');
+
+my $contact = $cust_pkg->contact_obj;
+
+sub pkg_change_contact_link {
+ my $cust_pkg = shift;
+ #my $pkgpart = $cust_pkg->pkgpart;
+ include( '/elements/popup_link-cust_pkg.html',
+ 'action' => $p. "misc/change_pkg_contact.html",
+ 'label' => emt('Change'), # contact'),
+ 'actionlabel' => emt('Change'),
+ 'cust_pkg' => $cust_pkg,
+ 'width' => 616,
+ 'height' => 220,
+ );
+}
+
+sub pkg_add_contact_link {
+ my $cust_pkg = shift;
+ #my $pkgpart = $cust_pkg->pkgpart;
+ include( '/elements/popup_link-cust_pkg.html',
+ 'action' => $p. "misc/change_pkg_contact.html",
+ 'label' => emt('Add contact'),
+ 'actionlabel' => emt('Change'),
+ 'cust_pkg' => $cust_pkg,
+ 'width' => 616,
+ 'height' => 192,
+ );
+}
+
+#sub edit_contact_link {
+# my $contactnum = shift;
+# include( '/elements/popup_link.html',
+# 'action' => $p. "edit/cust_contact.cgi?contactnum=$contactnum",
+# 'label' => emt('Edit contact'),
+# 'actionlabel' => emt('Edit'),
+# );
+#}
+
+</%init>
diff --git a/httemplate/view/cust_main/packages/location.html b/httemplate/view/cust_main/packages/location.html
index 34e3a64c3..f2d379841 100644
--- a/httemplate/view/cust_main/packages/location.html
+++ b/httemplate/view/cust_main/packages/location.html
@@ -1,7 +1,5 @@
-<TD CLASS="inv" BGCOLOR="<% $bgcolor %>" WIDTH="20%">
-
-% unless ( $cust_pkg->locationnum ) {
- <I><FONT SIZE=-1>(<% mt('default service address') |h %>)</FONT><BR>
+% if ( $default ) {
+ <DIV STYLE="font-style: italic; font-size: small">
% }
<% $loc->location_label( 'join_string' => '<BR>',
@@ -24,8 +22,8 @@
</FONT>
% }
-% unless ( $cust_pkg->locationnum ) {
- </I>
+% if ( $default ) {
+ </DIV>
% }
% if ( ! $cust_pkg->get('cancel')
@@ -41,19 +39,19 @@
</FONT>
% }
-</TD>
<%init>
my $conf = new FS::Conf;
my %opt = @_;
-my $bgcolor = $opt{'bgcolor'};
my $cust_pkg = $opt{'cust_pkg'};
my $countrydefault = $opt{'countrydefault'} || 'US';
my $statedefault = $opt{'statedefault'}
|| ($countrydefault eq 'US' ? 'CA' : '');
my $loc = $cust_pkg->cust_location_or_main;
+# dubious--they should all have a location now
+my $default = $cust_pkg->locationnum == $opt{'cust_main'}->ship_locationnum;
sub pkg_change_location_link {
my $cust_pkg = shift;
diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html
index 5d93ad46f..520305a9a 100644
--- a/httemplate/view/cust_main/packages/package.html
+++ b/httemplate/view/cust_main/packages/package.html
@@ -1,5 +1,6 @@
-<TD CLASS="inv" BGCOLOR="<% $bgcolor %>" VALIGN="top">
- <TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%">
+<TD CLASS="inv package" BGCOLOR="<% $bgcolor %>" VALIGN="top"
+ STYLE="border-left-width: <% $supplemental * 30 %>px">
+ <TABLE CLASS="inv package">
<TR>
<TD COLSPAN=2>
<A NAME="cust_pkg<% $cust_pkg->pkgnum %>"
@@ -17,50 +18,62 @@
<B><% $cust_pkg->quantity %></B>
</TD>
</TR>
-% }
+% }
<TR>
<TD COLSPAN=2>
<FONT SIZE=-1>
-% unless ( $cust_pkg->get('cancel') ) {
+% unless ( $cust_pkg->get('cancel') ) {
%
-% my $br = 0;
-% if ( $curuser->access_right('Change customer package') ) {
-% $br=1;
- (&nbsp;<%pkg_change_link($cust_pkg)%>&nbsp;)
-% }
+% if ( $supplemental or $part_pkg->freq eq '0' ) {
+% # Supplemental packages can't be changed independently.
+% # One-time charges don't need to be changed.
+% # For both of those, we only show "Edit dates", "Add comments",
+% # and "Add invoice details".
+% if ( $curuser->access_right('Edit customer package dates') ) {
+ (&nbsp;<%pkg_dates_link($cust_pkg)%>&nbsp;)
+% }
+% } else {
+% # the usual case: links to change package definition,
+% # discount, and customization
+% my $br = 0;
+% if ( $curuser->access_right('Change customer package') ) {
+% $br=1;
+ (&nbsp;<%pkg_change_link($cust_pkg)%>&nbsp;)
+% }
%
-% if ( $curuser->access_right('Edit customer package dates') ) {
-% $br=1;
- (&nbsp;<%pkg_dates_link($cust_pkg)%>&nbsp;)
-% }
+% if ( $curuser->access_right('Edit customer package dates') ) {
+% $br=1;
+ (&nbsp;<%pkg_dates_link($cust_pkg)%>&nbsp;)
+% }
%
-% if ( $curuser->access_right('Discount customer package')
-% && $part_pkg->can_discount
-% && ! scalar($cust_pkg->cust_pkg_discount_active)
-% && ! scalar($cust_pkg->part_pkg->part_pkg_discount)
-% )
-% {
-% $br=1;
- (&nbsp;<%pkg_discount_link($cust_pkg)%>&nbsp;)
-% }
+% if ( $curuser->access_right('Discount customer package')
+% && $part_pkg->can_discount
+% && ! scalar($cust_pkg->cust_pkg_discount_active)
+% && ! scalar($cust_pkg->part_pkg->part_pkg_discount)
+% )
+% {
+% $br=1;
+ (&nbsp;<%pkg_discount_link($cust_pkg)%>&nbsp;)
+% }
%
-% if ( $curuser->access_right('Customize customer package') ) {
-% $br=1;
- (&nbsp;<%pkg_customize_link($cust_pkg,$part_pkg)%>&nbsp;)
-% }
+% if ( $curuser->access_right('Customize customer package') ) {
+% $br=1;
+ (&nbsp;<%pkg_customize_link($cust_pkg,$part_pkg)%>&nbsp;)
+% }
%
- <% $br ? '<BR>' : '' %>
-% }
+ <% $br ? '<BR>' : '' %>
+% }
-% if ( $cust_pkg->num_cust_event
-% && ( $curuser->access_right('Billing event reports')
-% || $curuser->access_right('View customer billing events')
-% )
-% ) {
- (&nbsp;<%pkg_event_link($cust_pkg)%>&nbsp;)
-% }
+% if ( $cust_pkg->num_cust_event
+% && ( $curuser->access_right('Billing event reports')
+% || $curuser->access_right('View customer billing events')
+% )
+% ) {
+ (&nbsp;<%pkg_event_link($cust_pkg)%>&nbsp;)
+% }
+% } #!$supplemental
</FONT>
</TD>
@@ -170,15 +183,40 @@
</TR>
% if ( $curuser->access_right('Change customer package') and
% !$cust_pkg->get('cancel') and
-% !$opt{'show_location'}) {
+% !$supplemental and
+% $part_pkg->freq ne '0' ) {
<TR>
+% if ( FS::Conf->new->exists('invoice-unitprice') ) {
<TD><FONT SIZE="-1">
- (&nbsp;<% pkg_change_location_link($cust_pkg) %>&nbsp;)
+ (&nbsp;<% pkg_change_quantity_link($cust_pkg) %>&nbsp;)
</FONT></TD>
+% }
</TR>
% }
% }
</TABLE>
+% if ( @cust_pkg_usage ) {
+ <TABLE CLASS="usage inv">
+ <TR><TH COLSPAN=4><% mt('Included usage') %></TH></TR>
+% foreach my $usage (@cust_pkg_usage) {
+% my $part = $usage->part_pkg_usage;
+% my $ratio = 255 * ($usage->minutes / $part->minutes);
+% $ratio = 255 if $ratio > 255; # because rollover
+% my $color = sprintf('STYLE="font-weight: bold; color: #%02x%02x00"', 255 - $ratio, $ratio);
+% my $trstyle = '';
+% $trstyle = ' CLASS="shared"' if $part->shared;
+ <TR<%$trstyle%>>
+ <TD ALIGN="right"><% $part->description %>: </TD>
+ <TD <%$color%> ALIGN="right"><% $usage->minutes %></TD>
+ <TD <%$color%>> / </TD>
+ <TD <%$color%>><% $part->minutes %></TD>
+% if ( $part->shared ) {
+ <TD><I>(shared)</I></TD>
+% }
+ </TR>
+% }
+ </TABLE>
+% }
</TD>
@@ -196,6 +234,18 @@ my $countrydefault = $opt{'countrydefault'} || 'US';
my $statedefault = $opt{'statedefault'}
|| ($countrydefault eq 'US' ? 'CA' : '');
+my $supplemental = $opt{'supplemental'} || 0;
+
+$cust_pkg->pkgnum =~ /^(\d+)$/;
+my $pkgnum = $1;
+my @cust_pkg_usage = qsearch({
+ 'select' => 'cust_pkg_usage.*',
+ 'table' => 'cust_pkg_usage',
+ 'addl_from' => ' JOIN part_pkg_usage USING (pkgusagepart)',
+ 'extra_sql' => " WHERE pkgnum = $1",
+ 'order_by' => ' ORDER BY priority ASC, description ASC',
+});
+
#subroutines
#false laziness w/status.html
@@ -229,6 +279,17 @@ sub pkg_change_location_link {
);
}
+sub pkg_change_quantity_link {
+ include( '/elements/popup_link-cust_pkg.html',
+ 'action' => $p. 'edit/cust_pkg_quantity.html?',
+ 'label' => emt('Change quantity'),
+ 'actionlabel' => emt('Change'),
+ 'cust_pkg' => shift,
+ 'width' => 390,
+ 'height' => 220,
+ );
+}
+
sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', emt('Edit dates'), @_ ); }
sub pkg_discount_link {
diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html
index 85f0c795a..5f54c0a36 100755
--- a/httemplate/view/cust_main/packages/section.html
+++ b/httemplate/view/cust_main/packages/section.html
@@ -1,53 +1,48 @@
% if ( @$packages ) {
-% my $bgcolor1 = '#eeeeee';
-% my $bgcolor2 = '#ffffff';
-% my $bgcolor = '';
-
<TR>
% #my $width = $show_location ? 'WIDTH="25%"' : 'WIDTH="33%"';
<TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Package') |h %></TH>
<TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Status') |h %></TH>
-% if ( $show_location ) {
- <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Location') |h %></TH>
-% }
+ <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Contact/Location') |h %></TH>
<TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Services') |h %></TH>
</TR>
% #$FS::cust_pkg::DEBUG = 2;
% foreach my $cust_pkg (@$packages) {
+ <& .packagerow, $cust_pkg,
+ 'cust_main' => $opt{'cust_main'},
+ 'bgcolor' => $opt{'bgcolor'},
+ %conf_opt
+ &>
+% }
+% } else { # there are no packages
+<BR>
+% }
+<%def .packagerow>
%
-% if ( $bgcolor eq $bgcolor1 ) {
-% $bgcolor = $bgcolor2;
-% } else {
-% $bgcolor = $bgcolor1;
-% }
-%
-% my %iopt = (
-% 'bgcolor' => $bgcolor,
-% 'cust_pkg' => $cust_pkg,
-% 'part_pkg' => $cust_pkg->part_pkg,
-% 'cust_main' => $opt{'cust_main'},
-% %conf_opt,
-% );
-%
-
+% my ($cust_pkg, %iopt) = @_;
+% $iopt{'cust_pkg'} = $cust_pkg;
+% $iopt{'part_pkg'} = $cust_pkg->part_pkg;
<!--pkgnum: <% $cust_pkg->pkgnum %>-->
- <TR>
+ <TR CLASS="row<%$row % 2%>">
<& package.html, %iopt &>
- <& status.html, %iopt &>
-% if ( $show_location ) {
- <& location.html, %iopt &>
-% }
+ <& status.html, %iopt &>
+ <TD CLASS="inv" BGCOLOR="<% $iopt{bgcolor} %>" WIDTH="20%" VALIGN="top">
+ <& contact.html, %iopt &>
+ <& location.html, %iopt &>
+ </TD>
<& services.html, %iopt &>
</TR>
-
-% } #foreach $cust_pkg
-%# </TABLE>
-% } #if @$packages
-% else {
-<BR>
+% $row++;
+% # include supplemental packages if any
+% $iopt{'supplemental'} = ($iopt{'supplemental'} || 0) + 1;
+% foreach my $supp_pkg ($cust_pkg->supplemental_pkgs) {
+ <& .packagerow, $supp_pkg, %iopt &>
% }
-
+</%def>
+<%shared>
+my $row = 0;
+</%shared>
<%init>
my %opt = @_;
@@ -56,7 +51,6 @@ my $conf = new FS::Conf;
my $curuser = $FS::CurrentUser::CurrentUser;
my $packages = $opt{'packages'};
-my $show_location = $opt{'show_location'};
# Sort order is hardcoded for now, can change this if needed.
@$packages = sort {
@@ -89,10 +83,8 @@ my %conf_opt = (
'manage_link_loc' => scalar($conf->config('svc_broadband-manage_link_loc')),
'manage_link-new_window' => $conf->exists('svc_broadband-manage_link-new_window'),
'maestro-status_test' => $conf->exists('maestro-status_test'),
- 'cust_pkg-large_pkg_size' => $conf->config('cust_pkg-large_pkg_size'),
+ 'cust_pkg-large_pkg_size' => scalar($conf->config('cust_pkg-large_pkg_size')),
- # for packages.html Change location link
- 'show_location' => $show_location,
);
</%init>
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index e9017745b..9d5a88e0f 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -1,9 +1,11 @@
-<TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
+<TD CLASS="inv" BGCOLOR="<% $bgcolor %>" VALIGN="top">
<TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%">
%#this should use cust_pkg->status and cust_pkg->statuscolor eventually
-% if ( $cust_pkg->order_date ) {
+% if ( $supplemental ) {
+ <% pkg_status_row_colspan($cust_pkg, emt('Supplemental'), '', 'color' => '7777FF', %opt) %>
+% } elsif ( $cust_pkg->order_date ) {
<% pkg_status_row($cust_pkg, emt('Ordered'), 'order_date', %opt ) %>
% }
@@ -12,30 +14,25 @@
<% pkg_status_row($cust_pkg, emt('Cancelled'), 'cancel', 'color'=>'FF0000', %opt ) %>
- <% pkg_status_row_colspan( $cust_pkg,
- ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan,
- %opt
- )
- %>
+ <% pkg_reason_row($cust_pkg, $cpr, color => 'ff0000', %opt) %>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', 'colspan'=>$colspan, %opt, ) %>
+ <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', %opt, ) %>
% } else {
<% pkg_status_row( $cust_pkg, emt('Setup'), 'setup', %opt ) %>
- <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, emt('Suspended'), 'susp', %opt, curuser=>$curuser ) %>
% }
%
-% if ( $part_pkg->freq ) { #?
+% if ( $part_pkg->freq and !$supplemental ) { #?
<TR>
- <TD COLSPAN=<%$colspan%>>
+ <TD COLSPAN=<%$opt{colspan}%>>
<FONT SIZE=-1>
% if ( $curuser->access_right('Un-cancel customer package') ) {
(&nbsp;<% pkg_uncancel_link($cust_pkg) %>&nbsp;)
@@ -52,26 +49,21 @@
<% pkg_status_row( $cust_pkg, emt('Suspended'), 'susp', 'color'=>'FF9900', %opt ) %>
- <% pkg_status_row_colspan( $cust_pkg,
- ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
- 'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan,
- %opt,
- )
- %>
+ <% pkg_reason_row( $cust_pkg, $cpr, 'color' => 'FF9900', %opt ) %>
- <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
- <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_discount( $cust_pkg, %opt ) %>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', 'colspan'=>$colspan, %opt ) %>
+ <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', %opt ) %>
% } else {
<% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt ) %>
% }
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
- <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
% if ( $cust_pkg->option('suspend_bill', 1)
% || ( $part_pkg->option('suspend_bill', 1)
@@ -85,31 +77,33 @@
<% pkg_status_row_if( $cust_pkg, emt('Expires'), 'expire', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
- <TR>
- <TD COLSPAN=<%$colspan%>>
- <FONT SIZE=-1>
-% if ( $curuser->access_right('Unsuspend customer package') ) {
- (&nbsp;<% pkg_unsuspend_link($cust_pkg) %>&nbsp;)
- (&nbsp;<% pkg_resume_link($cust_pkg) %>&nbsp;)
-% }
-% if ( $curuser->access_right('Cancel customer package immediately') ) {
- (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
-% }
- </FONT>
- </TD>
- </TR>
-
+% if ( !$supplemental ) {
+ <TR>
+ <TD COLSPAN=<%$opt{colspan}%>>
+ <FONT SIZE=-1>
+% if ( $curuser->access_right('Unsuspend customer package') ) {
+ (&nbsp;<% pkg_unsuspend_link($cust_pkg) %>&nbsp;)
+ (&nbsp;<% pkg_resume_link($cust_pkg) %>&nbsp;)
+% }
+% if ( $curuser->access_right('Cancel customer package immediately') ) {
+ (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
+% }
+ </FONT>
+ </TD>
+ </TR>
+% }
+%
% } else { #status: active
%
% unless ( $cust_pkg->get('setup') ) { #not setup
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan( $cust_pkg, emt('Not yet billed (one-time charge)'), '', 'colspan'=>$colspan, %opt ) %>
+ <% pkg_status_row_colspan( $cust_pkg, emt('Not yet billed (one-time charge)'), '', %opt ) %>
- <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
- <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_discount( $cust_pkg, %opt ) %>
<% pkg_status_row_if(
$cust_pkg,
@@ -121,8 +115,9 @@
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
+% if (!$supplemental) {
<TR>
- <TD COLSPAN=<%$colspan%>>
+ <TD COLSPAN=<%$opt{colspan}%>>
<FONT SIZE=-1>
% if ( $curuser->access_right('Cancel customer package immediately') ) {
(&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
@@ -130,14 +125,15 @@
</FONT>
</TD>
</TR>
+% }
% } else {
- <% pkg_status_row_colspan($cust_pkg, emt("Not yet billed ($billed_or_prepaid [_1])", myfreq($part_pkg) ), '', 'colspan'=>$colspan, %opt ) %>
+ <% pkg_status_row_colspan($cust_pkg, emt("Not yet billed ($billed_or_prepaid [_1])", myfreq($part_pkg) ), '', %opt ) %>
- <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
- <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_discount( $cust_pkg, %opt ) %>
<% pkg_status_row_if($cust_pkg, emt('Start billing'), 'start_date', %opt) %>
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
@@ -148,13 +144,13 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan($cust_pkg, emt('One-time charge'), '', 'colspan'=>$colspan, %opt ) %>
+ <% pkg_status_row_colspan($cust_pkg, emt('One-time charge'), '', %opt ) %>
<% pkg_status_row($cust_pkg, emt('Billed'), 'setup', %opt) %>
- <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
- <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_discount( $cust_pkg, %opt ) %>
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
@@ -170,7 +166,7 @@
<% pkg_status_row_colspan( $cust_pkg,
emt('Overlimit'),
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color'=>'FFD000', 'colspan'=>$colspan,
+ 'color'=>'FFD000',
%opt
)
%>
@@ -179,15 +175,15 @@
<% pkg_status_row_colspan( $cust_pkg,
emt('Active'),
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
- 'color'=>'00CC00', 'colspan'=>$colspan,
+ 'color'=>'00CC00',
%opt
)
%>
% }
- <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
- <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_discount( $cust_pkg, %opt ) %>
<% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt) %>
@@ -202,7 +198,7 @@
% $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
% }
- <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+ <% pkg_status_row_changed( $cust_pkg, %opt ) %>
<% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if($cust_pkg, emt('Will automatically suspend by'), 'autosuspend', %opt) %>
@@ -212,10 +208,10 @@
<% pkg_status_row_if( $cust_pkg, emt('Expires'), 'expire', %opt, curuser=>$curuser ) %>
<% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
-% if ( $part_pkg->freq ) {
+% if ( $part_pkg->freq and !$supplemental ) {
<TR>
- <TD COLSPAN=<%$colspan%>>
+ <TD COLSPAN=<%$opt{colspan}%>>
<FONT SIZE=-1>
% if ( $curuser->access_right('Suspend customer package') ) {
(&nbsp;<% pkg_suspend_link($cust_pkg) %>&nbsp;)
@@ -251,8 +247,10 @@ my $bgcolor = $opt{'bgcolor'};
my $cust_pkg = $opt{'cust_pkg'};
my $part_pkg = $opt{'part_pkg'};
my $curuser = $FS::CurrentUser::CurrentUser;
-my $colspan = $opt{'cust_pkg-display_times'} ? 8 : 4;
my $width = $opt{'cust_pkg-display_times'} ? '38%' : '56%';
+my $supplemental = $opt{'supplemental'};
+
+$opt{colspan} = $opt{'cust_pkg-display_times'} ? 8 : 4;
#false laziness w/edit/REAL_cust_pkg.cgi
my( $billed_or_prepaid, $last_bill_or_renewed, $next_bill_or_prepaid_until );
@@ -285,9 +283,27 @@ sub pkg_link {
sub pkg_status_row {
my( $cust_pkg, $title, $field, %opt ) = @_;
+ if ( $field and $cust_pkg->main_pkgnum ) {
+ # for supplemental packages, we mostly only show these if they're
+ # different from the main package
+ my $main_pkg = $cust_pkg-> main_pkg;
+ if ( $main_pkg->get($field) ne $cust_pkg->get($field)
+ # with some exceptions
+ or $field eq 'bill'
+ or $field eq 'last_bill'
+ or $field eq 'setup'
+ or $field eq 'susp'
+ or $field eq 'cancel'
+ ) {
+ # handle it normally
+ } else {
+ return '';
+ }
+ }
+
my $color = $opt{'color'};
- my $html = qq(<TR><TD WIDTH="<%$width%>" ALIGN="right">);
+ my $html = qq(<TR><TD WIDTH="$width" ALIGN="right">);
$html .= qq(<FONT COLOR="#$color"><B>) if length($color);
$html .= qq($title&nbsp;);
$html .= qq(</B></FONT>) if length($color);
@@ -338,7 +354,6 @@ sub pkg_status_row_changed {
'',
'size' => '-1',
'align' => 'right',
- 'colspan' => $opt{'colspan'},
);
}
@@ -356,9 +371,7 @@ sub pkg_status_row_noauto {
return '' unless $cust_main->payby =~ /^(CARD|CHEK)$/;
my $what = lc(FS::payby->shortname($cust_main->payby));
- pkg_status_row_colspan( $cust_pkg, emt("No automatic $what charge"), '',
- 'colspan' => $opt{'colspan'},
- );
+ pkg_status_row_colspan( $cust_pkg, emt("No automatic $what charge"), '');
}
sub pkg_status_row_discount {
@@ -382,15 +395,24 @@ sub pkg_status_row_discount {
$cust_pkg_discount->pkgdiscountnum.
'">'.emt('remove discount').'</A>)</FONT>';
- $html .= pkg_status_row_colspan( $cust_pkg, $label, '',
- 'colspan' => $opt{'colspan'},
- );
+ $html .= pkg_status_row_colspan( $cust_pkg, $label, '', %opt );
}
$html;
}
+sub pkg_reason_row {
+ my ($cust_pkg, $cpr, %opt) = @_;
+ return '' if $cust_pkg->main_pkgnum;
+
+ my $reasontext = '';
+ $reasontext = $cpr->reasontext . ' by ' . $cpr->otaker if $cpr;
+ pkg_status_row_colspan( $cust_pkg, $reasontext, '',
+ 'align'=>'right', 'size'=>'-2', %opt
+ );
+}
+
sub pkg_status_row_colspan {
my($cust_pkg, $title, $addl, %opt) = @_;
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 942b42f54..915be49e5 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -34,7 +34,7 @@
<A HREF="<% $p %>edit/cust_pay.cgi?payby=WEST;custnum=<% $custnum %>"><% mt('Enter Western Union payment') |h %></A>
% }
-<BR>
+<% $s ? '<BR>' : '' %>
% $s=0;
% if ( ( $payby{'CARD'} || $payby{'DCRD'} )
@@ -58,11 +58,13 @@
<A HREF="<% $p %>edit/cust_pay.cgi?payby=MCRD;custnum=<% $custnum %>"><% mt('Post manual (offline/POS) credit card payment') |h %></A>
% }
-<BR>
+<% $s ? '<BR>' : '' %>
-%# credit link
+%# credit links
+% $s=0;
% if ( $curuser->access_right('Post credit') ) {
+ <% $s++ ? ' | ' : '' %>
<& /elements/popup_link-cust_main.html,
'label' => emt('Enter credit'),
'action' => "${p}edit/cust_credit.cgi",
@@ -70,7 +72,9 @@
'actionlabel' => emt('Enter credit'),
'width' => 616, #make room for reasons #540 default
&>
- |
+% }
+% if ( $curuser->access_right('Credit line items') ) {
+ <% $s++ ? ' | ' : '' %>
<& /elements/popup_link-cust_main.html,
'label' => emt('Credit line items'),
#'action' => "${p}search/cust_bill_pkg.cgi?nottax=1;type=select",
@@ -80,8 +84,8 @@
'width' => 968, #763,
'height' => 575,
&>
- <BR>
% }
+<% $s ? '<BR>' : '' %>
%# refund links
@@ -224,57 +228,20 @@
%#display payment history
-%my $money_char = $conf->config('money_char') || '$';
-%
-%sub balance_forward_row {
-% my( $b, $date, $money_char ) = @_;
-% ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/-&nbsp;\$/;
-
- <TR ID="balance_forward_row">
- <TD CLASS="grid" BGCOLOR="#dddddd">
- <% time2str($date_format, $date) %>
- </TD>
-
- <TD CLASS="grid" BGCOLOR="#dddddd">
- <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
- (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
- </TD>
-
- <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
- <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
- <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
- <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
- <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
-
- </TR>
-%}
-%
-%my $balance = 0;
%my %target = ();
%
-%my $years = $conf->config('payment_history-years') || 2;
-%my $older_than = time - $years * 31556926; #60*60*24*365.2422
%my $hidden = 0;
%my $seen = 0;
%my $old_history = 0;
%my $lastdate = 0;
%
-%foreach my $item ( sort { $a->{'date'} <=> $b->{'date'} } @history ) {
+%foreach my $item ( @history ) {
%
% $lastdate = $item->{'date'};
%
-% my $display;
-% if ( $item->{'date'} < $older_than ) {
+% my $display = '';
+% if ( $item->{'hide'} ) {
% $display = ' STYLE="display:none" ';
-% $hidden = 1;
-% } else {
-%
-% $display = '';
-%
-% if ( $hidden && ! $seen++ ) {
-% balance_forward_row($balance, $item->{'date'}, $money_char);
-% }
-%
% }
%
% if ( $bgcolor eq $bgcolor1 ) {
@@ -310,16 +277,8 @@
%
% my $target = exists($item->{'target'}) ? $item->{'target'} : '';
%
-% $balance += $item->{'charge'} if exists $item->{'charge'};
-% $balance -= $item->{'payment'} if exists $item->{'payment'};
-% $balance -= $item->{'credit'} if exists $item->{'credit'};
-% $balance += $item->{'refund'} if exists $item->{'refund'};
-% $balance = sprintf("%.2f", $balance);
-% $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
-% ( my $showbalance = $money_char. $balance ) =~ s/^\$\-/-&nbsp;\$/;
-%
-%
-
+% my $showbalance = $money_char . $item->{'balance'};
+% $showbalance =~ s/^\$\-/-&nbsp;\$/;
<TR <% $display ? $display.' ID="old_history'.$old_history++.'"' : ''%>>
<TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>">
@@ -355,11 +314,11 @@
<% $showbalance %>
</TD>
</TR>
-% }
-%if ( scalar(@history) && $hidden && ! $seen++ ) {
-% balance_forward_row($balance, $lastdate, $money_char);
-%}
+% if ( $item->{'balance_forward'} ) {
+<& .balance_forward_row, $item->{'balance'}, $item->{'date'} &>
+% }
+%} # foreach $item
</TABLE>
</TD>
@@ -382,14 +341,37 @@ function show_history () {
}
</SCRIPT>
+<%def .balance_forward_row>
+% my( $b, $date ) = @_;
+% ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/-&nbsp;\$/;
-<%init>
+ <TR ID="balance_forward_row">
+ <TD CLASS="grid" BGCOLOR="#dddddd">
+ <% time2str($date_format, $date) %>
+ </TD>
-my( $cust_main ) = @_;
-my $custnum = $cust_main->custnum;
+ <TD CLASS="grid" BGCOLOR="#dddddd">
+ <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
+ (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
+ </TD>
+
+ <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
+ <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
+ <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
+ <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
+ <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
+ </TR>
+</%def>
+<%shared>
my $conf = new FS::Conf;
my $date_format = $conf->config('date_format') || '%m/%d/%Y';
+my $money_char = $conf->config('money_char') || '$';
+</%shared>
+<%init>
+
+my( $cust_main ) = @_;
+my $custnum = $cust_main->custnum;
my $curuser = $FS::CurrentUser::CurrentUser;
@@ -497,6 +479,17 @@ foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
#'target' => $target, #XXX
};
}
+#declined batch payments
+foreach my $cust_pay_batch (
+ $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
+) {
+ my $pay_batch = $cust_pay_batch->pay_batch;
+ push @history, {
+ 'date' => $pay_batch->upload,
+ 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
+ 'void_payment' => $cust_pay_batch->amount,
+ };
+}
#credits (some false laziness w/payments)
foreach my $cust_credit ($cust_main->cust_credit) {
@@ -518,6 +511,41 @@ foreach my $cust_refund ($cust_main->cust_refund) {
}
+# sort in forward order first, and calculate running balances
+my $years = $conf->config('payment_history-years') || 2;
+my $older_than = time - $years * 31556926; #60*60*24*365.2422
+my $balance = 0;
+
+@history = sort { $a->{date} <=> $b->{date} } @history;
+my $i = 0;
+my $balance_forward;
+foreach my $item (@history) {
+ $balance += $item->{'charge'} if exists $item->{'charge'};
+ $balance -= $item->{'payment'} if exists $item->{'payment'};
+ $balance -= $item->{'credit'} if exists $item->{'credit'};
+ $balance += $item->{'refund'} if exists $item->{'refund'};
+ $balance = sprintf("%.2f", $balance);
+ $balance =~ s/^\-0\.00$/0.00/;
+ $item->{'balance'} = $balance;
+
+ if ( $item->{'date'} < $older_than ) {
+ $item->{'hide'} = 1;
+ } elsif ( $history[$i-1]->{'hide'} ) {
+ # this is the end of the hidden section
+ $history[$i-1]->{'balance_forward'} = 1;
+ }
+ $i++;
+}
+if ( @history and $history[-1]->{'hide'} ) {
+ # then everything is hidden
+ $history[-1]->{'balance_forward'} = 1;
+}
+
+# then sort in user-pref order
+if ( $curuser->option('history_order') eq 'newest' ) {
+ @history = sort { $b->{date} <=> $a->{date} } @history;
+} # else it's already oldest-first, and there are no other options yet
+
sub translate_payby {
my ($payby,$payinfo) = (shift,shift);
my %payby = (
diff --git a/httemplate/view/cust_main/payment_history/attempted_batch_payment.html b/httemplate/view/cust_main/payment_history/attempted_batch_payment.html
new file mode 100644
index 000000000..95947f512
--- /dev/null
+++ b/httemplate/view/cust_main/payment_history/attempted_batch_payment.html
@@ -0,0 +1,13 @@
+<I><% mt('Payment attempt') |h %> <% $info |h %></I>
+<%init>
+
+my( $cust_pay_batch, %opt ) = @_;
+
+my ($payby,$payinfo) = translate_payinfo($cust_pay_batch);
+$payby = translate_payby($payby,$payinfo);
+my $info = $payby ? "($payby$payinfo)" : '';
+
+$info .= ': '. $cust_pay_batch->error_message
+ if length($cust_pay_batch->error_message);
+
+</%init>
diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html
index f7c685c28..d735195fe 100644
--- a/httemplate/view/elements/svc_Common.html
+++ b/httemplate/view/elements/svc_Common.html
@@ -52,26 +52,39 @@ function areyousure(href) {
<% mt('Service #') |h %><B><% $svcnum %></B>
% my $url = $opt{'edit_url'} || $p. 'edit/'. $opt{'table'}. '.cgi?';
-| <& /view/elements/svc_edit_link.html, 'svc' => $svc_x, 'edit_url' => $url &>
+<& /view/elements/svc_edit_link.html, 'svc' => $svc_x, 'edit_url' => $url &>
<BR>
<% ntable("#cccccc") %><TR><TD><% ntable("#cccccc",2) %>
+% my @inventory_items = $svc_x->inventory_item;
% foreach my $f ( @$fields ) {
%
-% my($field, $type, $value, $hack_strict_refs);
+% my($field, $type, $value);
% if ( ref($f) ) {
% $field = $f->{'field'};
-% $hack_strict_refs = \&{ $f->{'value'} } if $f->{'value'};
-% $value = $f->{'value'} ? &$hack_strict_refs($svc_x) : $svc_x->$field;
% $type = $f->{'type'} || 'text';
+% if ( $f->{'value_callback'} ) {
+% my $hack_strict_refs = \&{ $f->{'value_callback'} };
+% $value = &$hack_strict_refs($svc_x);
+% } else {
+% $value = exists($f->{'value'}) ? $f->{'value'} : $svc_x->$field;
+% }
% } else {
% $field = $f;
-% $value = $svc_x->$field;
% $type = 'text';
+% $value = $svc_x->$field;
% }
%
% my $columndef = $part_svc->part_svc_column($field);
+% if ( $columndef->columnflag =~ /^[MA]$/ && $columndef->columnvalue =~ /,/ )
+% {
+% # inventory-select field with multiple classes
+% # show the class name to disambiguate
+% my ($item) = grep { $_->svc_field eq $field } @inventory_items;
+% my $class = qsearchs('inventory_class', { classnum => $item->classnum });
+% $value .= ' <i>('. $class->classname . ')</i>' if $class;
+% }
% unless ($columndef->columnflag eq 'F' && !length($columndef->columnvalue)) {
<TR>
diff --git a/httemplate/view/elements/svc_devices.html b/httemplate/view/elements/svc_devices.html
index d71c82f07..38c6d0919 100644
--- a/httemplate/view/elements/svc_devices.html
+++ b/httemplate/view/elements/svc_devices.html
@@ -12,91 +12,86 @@
)
</%doc>
-<% $devices %>
+%if ( @devices || $num_part_device || $table eq 'dsl_device' ) {
+% my $svcnum = $svc_x->svcnum;
+
+ Devices
+ (<A HREF="<%$p%>edit/<%$table%>.html?svcnum=<%$svcnum%>">Add device</A>)
+ <BR>
+
+% if ( @devices ) {
+
+ <SCRIPT>
+ function areyousure(href) {
+ if (confirm("Are you sure you want to delete this device?") == true)
+ window.location.href = href;
+ }
+ </SCRIPT>
+
+ <& /elements/table-grid.html &>
+ <TR>
+% if ( $table eq 'phone_device' ) {
+ <TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>
+% }
+ <TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
+ </TR>
+
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor = '';
+%
+% foreach my $device ( @devices ) {
+%
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+%
+% my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">);
+%
+% my $devicenum = $device->devicenum;
+% my $export_links = '';
+% $export_links = join( '<BR>', @{ $device->export_links } )
+% if $device->can('export_links');
+
+ <TR>
+% if ( $table eq 'phone_device' ) { #$devices->can('part_device')
+ <% $td %><% $device->part_device->devicename |h %></TD>
+% }
+ <% $td %><% $device->mac_addr %></TD>
+ <% $td %><% $export_links %></TD>
+ <% $td %>(
+% unless ( $opt{'no_edit'} ) {
+ <A HREF="<%$p%>edit/<%$table%>.html?<%$devicenum%>">edit</A> |
+% }
+ <A HREF="javascript:areyousure('<%$p%>misc/delete-<%$table%>.html?<%$devicenum%>')">delete</A>
+ )</TD>
+ </TR>
+% }
+ </TABLE>
+ <BR>
+
+% }
+ <BR>
+%}
<%init>
- my %opt = @_;
- my $table = $opt{'table'}; #part_device, dsl_device
- my $svc_x = $opt{'svc_x'};
-
- my $devices = '';
-
- my $num_part_device = 0;
- if ( $table eq 'phone_device' ) {
- my $sth = dbh->prepare("SELECT COUNT(*) FROM part_device")
- #WHERE disabled = '' OR disabled IS NULL;");
- or die dbh->errstr;
- $sth->execute or die $sth->errstr;
- $num_part_device = $sth->fetchrow_arrayref->[0];
+my %opt = @_;
+my $table = $opt{'table'}; #part_device, dsl_device
+my $svc_x = $opt{'svc_x'};
+
+my $num_part_device = 0;
+if ( $table eq 'phone_device' ) {
+ my $sth = dbh->prepare("SELECT COUNT(*) FROM part_device")
+ #WHERE disabled = '' OR disabled IS NULL;");
+ or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ $num_part_device = $sth->fetchrow_arrayref->[0];
}
- my @devices = $svc_x->$table();
-
- #should move the below to proper mason code above instead of making $devices
- if ( @devices || $num_part_device || $table eq 'dsl_device' ) {
- my $svcnum = $svc_x->svcnum;
- $devices .=
- qq[Devices (<A HREF="${p}edit/$table.html?svcnum=$svcnum">Add device</A>)<BR>];
- if ( @devices ) {
-
- $devices .= qq!
- <SCRIPT>
- function areyousure(href) {
- if (confirm("Are you sure you want to delete this device?") == true)
- window.location.href = href;
- }
- </SCRIPT>
- !;
-
-
- $devices .=
- include('/elements/table-grid.html').
- '<TR>';
-
- $devices .=
- '<TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>'
- if $table eq 'phone_device';
-
- $devices .=
- '<TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>'.
- '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'.
- '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'.
- '</TR>';
- my $bgcolor1 = '#eeeeee';
- my $bgcolor2 = '#ffffff';
- my $bgcolor = '';
-
- foreach my $device ( @devices ) {
-
- if ( $bgcolor eq $bgcolor1 ) {
- $bgcolor = $bgcolor2;
- } else {
- $bgcolor = $bgcolor1;
- }
- my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">);
-
- my $devicenum = $device->devicenum;
- my $export_links = join( '<BR>', @{ $device->export_links } )
- if $device->can('export_links');
-
- $devices .= '<TR>';
- $devices .= $td. $device->part_device->devicename. '</TD>'
- if $table eq 'phone_device'; #$devices->can('part_device');
-
- $devices .= $td. $device->mac_addr. '</TD>'.
- $td. $export_links. '</TD>'.
- "$td( ";
-
- $devices .= qq(<A HREF="${p}edit/$table.html?$devicenum">edit</A> | )
- unless $opt{'no_edit'};
-
- $devices .= qq(<A HREF="javascript:areyousure('${p}misc/delete-$table.html?$devicenum')">delete</A>).
- ' )</TD>'.
- '</TR>';
- }
- $devices .= '</TABLE><BR>';
- }
- $devices .= '<BR>';
- }
+my @devices = $svc_x->$table();
</%init>
diff --git a/httemplate/view/elements/svc_edit_link.html b/httemplate/view/elements/svc_edit_link.html
index d65db0a8f..5438ed266 100644
--- a/httemplate/view/elements/svc_edit_link.html
+++ b/httemplate/view/elements/svc_edit_link.html
@@ -7,8 +7,12 @@ function areyousure_delete() {
window.location.href = '<% $cancel_url %>';
}
</SCRIPT>
-<A HREF="<% $edit_url %>"><% mt("Edit this [_1]", $label) |h %></A> |
-<A HREF="javascript:areyousure_delete()"><% mt('Unprovision this Service') |h %></A>
+% if ( $curuser->access_right('Provision customer service') ) {
+| <A HREF="<% $edit_url %>"><% mt("Edit this [_1]", $label) |h %></A>
+% }
+% if ( $curuser->access_right('Unprovision customer service') ) {
+| <A HREF="javascript:areyousure_delete()"><% mt('Unprovision this Service') |h %></A>
+% }
% }
<%init>
my %opt = @_;
@@ -20,4 +24,5 @@ my $cancel_url = $p . 'misc/unprovision.cgi?' . $svc_x->svcnum;
my $cust_svc = $svc_x->cust_svc; # always exists
my $cancel_date = $cust_svc->pkg_cancel_date;
my ($label) = $cust_svc->label;
+my $curuser = $FS::CurrentUser::CurrentUser;
</%init>
diff --git a/httemplate/view/elements/svc_export_status.html b/httemplate/view/elements/svc_export_status.html
index d96bb277d..4ce869e27 100644
--- a/httemplate/view/elements/svc_export_status.html
+++ b/httemplate/view/elements/svc_export_status.html
@@ -7,7 +7,15 @@
% foreach my $key ( sort {$a cmp $b} keys %$hashref ) {
<TR>
<TD ALIGN="right"><% $key |h %></TD>
- <TD BGCOLOR="#ffffff"><% $hashref->{$key} |h %></TD>
+ <TD BGCOLOR="#ffffff">
+% if ( ref($hashref->{$key}) eq 'ARRAY' ) {
+% foreach (@{ $hashref->{$key} }) {
+ <% $_ |h %><BR>
+% }
+% } else {
+ <% $hashref->{$key} |h %>
+% }
+ </TD>
</TR>
% }
diff --git a/httemplate/view/quotation-pdf.cgi b/httemplate/view/quotation-pdf.cgi
new file mode 100755
index 000000000..7f62ce173
--- /dev/null
+++ b/httemplate/view/quotation-pdf.cgi
@@ -0,0 +1,29 @@
+<% $content %>\
+<%init>
+
+#false laziness w/elements/cust_bill-typeset
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Generate quotation'); #View quotations ?
+
+my $quotationnum = $cgi->param('quotationnum');
+
+my $conf = new FS::Conf;
+
+my $quotation = qsearchs({
+ 'select' => 'quotation.*',
+ 'table' => 'quotation',
+ #'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'quotationnum' => $quotationnum },
+ #'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+});
+die "Quotation #$quotationnum not found!" unless $quotation;
+
+my $content = $quotation->print_pdf(); #\%opt);
+
+http_header('Content-Type' => 'application/pdf');
+http_header('Content-Disposition' => "filename=$quotationnum.pdf" );
+http_header('Content-Length' => length($content) );
+http_header('Cache-control' => 'max-age=60' );
+
+</%init>
diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi
index 199591356..858ccbe67 100755
--- a/httemplate/view/svc_acct.cgi
+++ b/httemplate/view/svc_acct.cgi
@@ -22,6 +22,7 @@
% }
+
<& svc_acct/radius_usage.html,
'svc_acct' => $svc_acct,
'part_svc' => $part_svc,
@@ -29,6 +30,7 @@
%gopt,
&>
+
<& svc_acct/change_svc_form.html,
'part_svc' => \@part_svc,
'svcnum' => $svcnum,
@@ -37,13 +39,15 @@
&>
<% mt('Service #') |h %><B><% $svcnum %></B>
-|
<& /view/elements/svc_edit_link.html, 'svc' => $svc_acct &>
<& svc_acct/change_svc.html,
'part_svc' => \@part_svc,
%gopt,
&>
+</FORM>
+
+
<& svc_acct/basics.html,
'svc_acct' => $svc_acct,
'part_svc' => $part_svc,
@@ -90,8 +94,12 @@ die "access denied"
my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
' LEFT JOIN cust_pkg USING ( pkgnum ) '.
' LEFT JOIN cust_main USING ( custnum ) ';
-
-my($query) = $cgi->keywords;
+my $query;
+if ( $cgi->keywords ) {
+ ($query) = $cgi->keywords;
+} else {
+ $query = $cgi->param('svcnum');
+}
$query =~ /^(\d+)$/;
my $svcnum = $1;
my $svc_acct = qsearchs({
diff --git a/httemplate/view/svc_acct/basics.html b/httemplate/view/svc_acct/basics.html
index 2d9953fcc..04e7bcff8 100644
--- a/httemplate/view/svc_acct/basics.html
+++ b/httemplate/view/svc_acct/basics.html
@@ -20,7 +20,7 @@
% if ( $password =~ /^\*\w+\* (.*)$/ ) {
% $password = $1;
% $show_pw .= '<I>('. mt('login disabled') .')</I> ';
-% }
+% }
% if ( ! $password
% && $svc_acct->_password_encryption ne 'plain'
% && $svc_acct->_password
@@ -28,13 +28,27 @@
% {
% $show_pw .= '<I>('. uc($svc_acct->_password_encryption). ' '.mt('encrypted').')</I>';
% } elsif ( $conf->exists('showpasswords') ) {
-% $show_pw .= '<PRE>'. encode_entities($password). '</PRE>';
+% $show_pw .= '<SPAN >'. encode_entities($password). '</PRE>';
% } else {
+% $password = '';
% $show_pw .= '<I>('. mt('hidden') .')</I>';
-% }
-% $password = '';
-<& /view/elements/tr.html, label=>mt('Password'), value=>$show_pw &>
-
+% }
+<TR>
+ <TD ALIGN="right"><% mt('Password') %></TD>
+ <TD STYLE="background-color: #ffffff; white-space: nowrap">
+ <% $show_pw %>
+% my $curuser = $FS::CurrentUser::CurrentUser;
+% if ( $curuser->access_right('Provision customer service') or
+% ($curuser->access_right('Edit password') and
+% ! $part_svc->restrict_edit_password) )
+% {
+ <& /elements/change_password.html,
+ 'svc_acct' => $svc_acct,
+ 'curr_value' => $password,
+ &>
+% }
+ </TD>
+</TR>
% if ( $conf->exists('security_phrase') ) {
<& /view/elements/tr.html, label=>mt('Security phrase'), value=>$svc_acct->sec_phrase &>
diff --git a/httemplate/view/svc_broadband.cgi b/httemplate/view/svc_broadband.cgi
index 75e673c4f..7d6520e57 100644
--- a/httemplate/view/svc_broadband.cgi
+++ b/httemplate/view/svc_broadband.cgi
@@ -26,23 +26,31 @@ $labels{'coordinates'} = 'Latitude/Longitude';
my @fields = (
'description',
- { field => 'routernum', value => \&router },
+ { field => 'routernum', value_callback => \&router },
'speed_down',
'speed_up',
- { field => 'ip_addr', value => \&ip_addr },
- { field => 'sectornum', value => \&sectornum },
- { field => 'mac_addr', value => \&mac_addr },
+ { field => 'ip_addr', value_callback => \&ip_addr },
+ { field => 'sectornum', value_callback => \&sectornum },
+ { field => 'mac_addr', value_callback => \&mac_addr },
#'latitude',
#'longitude',
- { field => 'coordinates', value => \&coordinates },
+ { field => 'coordinates', value_callback => \&coordinates },
'altitude',
+
+ 'radio_serialnum',
+ 'radio_location',
+ 'poe_location',
+ 'rssi',
+ 'suid',
+ { field => 'shared_svcnum', value_callback=> \&shared_svcnum, }, #value_callback =>
+
'vlan_profile',
'authkey',
'plan_id',
);
push @fields,
- { field => 'usergroup', value => \&usergroup }
+ { field => 'usergroup', value_callback => \&usergroup }
if $conf->exists('svc_broadband-radius');
sub router {
@@ -112,9 +120,36 @@ sub coordinates {
);
}
+sub shared_svcnum {
+ my $svc_broadband = shift;
+ return '' unless $svc_broadband->shared_svcnum;
+
+ my $shared_svc_broadband =
+ qsearchs('svc_broadband', { 'svcnum' => $svc_broadband->shared_svcnum,
+ }
+ #agent virt?
+ )
+ or return '';
+ my $shared_cust_pkg = $shared_svc_broadband->cust_svc->cust_pkg;
+
+ $shared_svc_broadband->label.
+ ( $shared_cust_pkg
+ ? ' ('. $shared_cust_pkg->cust_main->name. ')'
+ : ''
+ );
+}
+
sub svc_callback {
# trying to move to the callback style
my ($cgi, $svc_x, $part_svc, $cust_pkg, $fields, $opt) = @_;
+
+ if ( $part_svc->part_svc_column('latitude')->columnflag eq 'F'
+ && $part_svc->part_svc_column('longitude')->columnflag eq 'F'
+ )
+ {
+ @$fields = grep { !ref($_) || $_->{field} ne 'coordinates' } @$fields;
+ }
+
# again, we assume at most one of these exports per part_svc
my ($nas_export) = $part_svc->part_export('broadband_nas');
if ( $nas_export ) {
diff --git a/httemplate/view/svc_cert.cgi b/httemplate/view/svc_cert.cgi
index 0cd66b422..964b808ab 100644
--- a/httemplate/view/svc_cert.cgi
+++ b/httemplate/view/svc_cert.cgi
@@ -17,7 +17,7 @@ my %labels = map { $_ => ( ref($fields->{$_})
my @fields = (
{ field=>'privatekey',
- value=> sub {
+ value_callback=> sub {
my $svc_cert = shift;
if ( $svc_cert->privatekey && $svc_cert->check_privatekey ) {
'<FONT COLOR="#33ff33">Verification OK</FONT>';
@@ -31,7 +31,7 @@ my @fields = (
qw( common_name organization organization_unit city state country cert_contact
),
{ 'field'=>'csr',
- 'value'=> sub {
+ 'value_callback'=> sub {
my $svc_cert = shift;
if ( $svc_cert->csr ) {
@@ -67,7 +67,7 @@ my @fields = (
},
},
{ 'field'=>'certificate',
- 'value'=> sub {
+ 'value_callback'=> sub {
my $svc_cert = shift;
if ( $svc_cert->certificate ) {
@@ -137,7 +137,7 @@ my @fields = (
},
},
{ 'field'=>'cacert',
- 'value'=> sub {
+ 'value_callback'=> sub {
my $svc_cert = shift;
if ( $svc_cert->cacert ) {
diff --git a/httemplate/view/svc_hardware.cgi b/httemplate/view/svc_hardware.cgi
index 7f5e889d8..eef1c1140 100644
--- a/httemplate/view/svc_hardware.cgi
+++ b/httemplate/view/svc_hardware.cgi
@@ -13,17 +13,20 @@ my %labels = map { $_ => ( ref($fields->{$_})
: $fields->{$_}
);
} keys %$fields;
+
+$labels{'display_hw_addr'} = 'Hardware address';
+
my $model = { field => 'typenum',
type => 'text',
- value => sub { $_[0]->hardware_type->description }
+ value_callback => sub { $_[0]->hardware_type->description }
};
my $status = { field => 'statusnum',
type => 'text',
- value => sub { $_[0]->status_label }
+ value_callback => sub { $_[0]->status_label }
};
my $note = { field => 'note',
type => 'text',
- value => sub { encode_entities($_[0]->note) }
+ value_callback => sub { encode_entities($_[0]->note) }
};
my @fields = (
diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi
index 323be63dc..ed95c4cea 100644
--- a/httemplate/view/svc_phone.cgi
+++ b/httemplate/view/svc_phone.cgi
@@ -16,9 +16,20 @@ my %labels = map { $_ => ( ref($fields->{$_})
);
} keys %$fields;
-my @fields = qw( countrycode phonenum );
+my @fields = qw( countrycode phonenum sim_imsi );
push @fields, 'domain' if $conf->exists('svc_phone-domain');
-push @fields, qw( pbx_title sip_password pin phone_name forwarddst email );
+push @fields, qw( pbx_title );
+
+if ( $conf->exists('showpasswords') ) {
+ push @fields, qw( sip_password );
+} else {
+ push @fields, { 'field' => 'sip_password', #'_HIDDEN_sip_password',
+ 'type' => 'fixed',
+ 'value' => '<I>('. mt('hidden') .')</I>',
+ };
+}
+
+push @fields, qw( pin phone_name forwarddst email );
if ( $conf->exists('svc_phone-lnp') ) {
push @fields, 'lnp_status',