diff options
Diffstat (limited to 'httemplate/view')
31 files changed, 929 insertions, 416 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.cgi b/httemplate/view/cust_main.cgi index ec3191971..430c50c5f 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -91,24 +91,23 @@ function areyousure(href, message) { &> | % } -% if ( $curuser->access_right('Merge customer') ) { +% if ( $curuser->access_right('Merge customer') +% and ( scalar($cust_main->ncancelled_pkgs) +% # || we start supporting payment info merge again in some way +% ) +% ) +% { <& /elements/popup_link-cust_main.html, { 'action' => $p. 'misc/merge_cust.html', 'label' => emt('Merge this customer'), 'actionlabel' => emt('Merge customer'), 'cust_main' => $cust_main, - 'width' => 480, - 'height' => 192, + 'width' => 569, + 'height' => 210, } &> | % } -% if ( $conf->exists('deletecustomers') -% && $curuser->access_right('Delete customer') -% ) { - <A HREF="<% $p %>misc/delete-customer.cgi?<% $custnum%>"><% mt('Delete this customer') |h %></A> | -% } - % unless ( $conf->exists('disable_customer_referrals') ) { <A HREF="<% $p %>edit/cust_main.cgi?referral_custnum=<% $custnum %>"><% mt('Refer a new customer') |h %></A> | <A HREF="<% $p %>search/cust_main.cgi?referral_custnum=<% $custnum %>"><% mt('View this customer\'s referrals') |h %></A> @@ -157,11 +156,6 @@ function areyousure(href, message) { <BR><BR> % } -%if ( $conf->exists('maestro-status_test') ) { - <A HREF="<% $p %>misc/maestro-customer_status-test.html?<% $custnum %>"><% mt('Test maestro status') |h %></A> - <BR><BR> -% } - <A NAME="cust_main"></A> <TABLE BORDER=0> <TR> diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index 5c46803d2..e286305f4 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> % } @@ -300,6 +304,13 @@ </TR> % } +% if ( $cust_main->currency ) { + <TR> + <TD ALIGN="right"><% mt('Invoicing currency') |h %></TD> + <TD BGCOLOR="#ffffff"><% $cust_main->currency. ': '. code2currency($cust_main->currency) %></TD> + </TR> +% } + % if ( $cust_main->locale ) { % my %locale_info = FS::Locales->locale_info($cust_main->locale); <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/locations.html b/httemplate/view/cust_main/locations.html index b29d0ce4d..7eb52ca46 100755 --- a/httemplate/view/cust_main/locations.html +++ b/httemplate/view/cust_main/locations.html @@ -28,15 +28,19 @@ STYLE="padding-bottom: 0px; % } <% $loc->location_label %></SPAN> <SPAN STYLE="float:right;"> -% if ( $locationnum and !$loc->disabled ) { +% if ( $locationnum && !$loc->disabled && ! $opt{no_links} ) { <% edit_location_link($locationnum) %> % } -% if ( $locationnum and !$loc->disabled and !$active{$locationnum} ) { +% if ( $locationnum && !$loc->disabled && !$active{$locationnum} && ! $opt{no_links} ) { <% disable_location_link($locationnum) %> % } </SPAN></TH></TR> % if (@$packages) { -<& packages/section.html, 'packages' => $packages &> + <& packages/section.html, + 'packages' => $packages, + 'cust_main' => $cust_main, + 'no_links' => $opt{no_links} + &> % } </TABLE><BR> % } #foreach $locationnum diff --git a/httemplate/view/cust_main/notes.html b/httemplate/view/cust_main/notes.html index 1e9f464db..2de68ff46 100755 --- a/httemplate/view/cust_main/notes.html +++ b/httemplate/view/cust_main/notes.html @@ -63,7 +63,11 @@ % % my $edit = ''; % if ($curuser->access_right('Edit customer note') ) { -% $edit = qq! <A HREF="javascript:void(0);" $clickjs>(!.emt('edit').')</A>'; +% my $delete_url = $fsurl.'misc/delete-note.html?'.$notenum; +% $edit = qq! <A HREF="javascript:void(0);" $clickjs>(!.emt('edit').')</A>'. +% qq! <A HREF="$delete_url" !. +% qq! onclick="return confirm('Delete this note?')">!. +% '('.emt('delete').')</A>'; % } % % if ( $last_classnum != $note->classnum && !$skipheader ) { diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 7d7930634..e32fe4c03 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -1,4 +1,33 @@ -% my $s = 0; +<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> + +% unless ( $opt{no_links} ) { + +% my $s = 0; % if ( $curuser->access_right('Qualify service') ) { <% $s++ ? ' | ' : '' %> @@ -17,21 +46,33 @@ <& one_time_charge_link.html, $cust_main &> % } +% if ( $curuser->access_right('Bulk move customer services') ) { + <% $s++ ? ' | ' : '' %> + + <& /elements/popup_link-cust_main.html, + 'label' => emt('Move services between packages'), + 'action' => "${p}edit/bulk-cust_svc-pkgnum.html", + 'cust_main' => $cust_main, + 'actionlabel' => emt('Move services'), + 'width' => 968, #763, + 'height' => 575, + &> + +% } + % if ( $curuser->access_right('Bulk change customer packages') ) { <% $s++ ? ' | ' : '' %> - <A HREF="<% $p %>edit/cust_pkg.cgi?<% $cust_main->custnum %>"><% mt('Bulk order and cancel packages') |h %></A> (<% mt('preserves services') |h %>) + <A HREF="<% $p %>edit/cust_pkg.cgi?<% $cust_main->custnum %>"><% mt('Bulk order and cancel packages') |h %></A> % } <BR><BR> +% } # unless $opt{no_links} + <TABLE> <TR> <TD ALIGN="left" VALIGN="top"> -% if ( @$packages ) { - -<% mt('Current packages') |h %> -% } % if ( $cust_main->num_cancelled_pkgs ) { % if ( $cgi->param('showcancelledpackages') eq '0' #see if it was set by me % || ( $conf->exists('hidecancelledpackages') @@ -60,6 +101,9 @@ % } </TD> + +% unless ( $opt{no_links} ) { + <TD ALIGN="right"> <A HREF="<%$p%>search/report_cust_pkg.html?custnum=<% $cust_main->custnum %>"><% mt('Package reports') |h %></A> % if ( $curuser->access_right('Qualify service') ) { @@ -71,14 +115,18 @@ <% mt('Usage reports:') |h %> <A HREF="<%$p%>search/report_cdr.html?custnum=<% $cust_main->custnum %>"><% mt('CDRs') |h %></A> </TD> + +% } # unless $opt{no_links} + </TR> <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, + %opt, &> % } % else { @@ -87,7 +135,7 @@ <& packages/section.html, 'cust_main' => $cust_main, 'packages' => $packages, - 'show_location' => $show_location, + %opt, &> </TABLE> % } @@ -114,10 +162,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 +222,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..93985e404 --- /dev/null +++ b/httemplate/view/cust_main/packages/contact.html @@ -0,0 +1,87 @@ +% if ( $contact ) { + <% $contact->line |h %> +% if ( $show_change_link && ! $opt{no_links} ) { + <FONT SIZE=-1> + ( <%pkg_change_contact_link($cust_pkg)%> ) + </FONT> +% } +% if ( $show_detach_link && ! $opt{no_links} ) { + <FONT SIZE=-1> + ( <%pkg_detach_link($cust_pkg)%> ) + </FONT> +% } +% } elsif ( $show_contact_link && ! $opt{no_links} ) { + <FONT SIZE=-1> + ( <%pkg_add_contact_link($cust_pkg)%> ) + </FONT> +% } +<%init> + +my $conf = new FS::Conf; +my %opt = @_; + +my $cust_pkg = $opt{'cust_pkg'}; + +my $show_change_link = + ! $cust_pkg->get('cancel') + && $FS::CurrentUser::CurrentUser->access_right('Change customer package'); + +my $show_detach_link = + ! $cust_pkg->get('cancel') + && $FS::CurrentUser::CurrentUser->access_right('Detach customer package'); + +my $show_contact_link = + ! $cust_pkg->get('cancel') + ; #&& $FS::CurrentUser::CurrentUser->access_right('Add package contact'); #or something like that + +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('Add contact'), + 'cust_pkg' => $cust_pkg, + 'width' => 616, + 'height' => 192, + ); +} + +sub pkg_detach_link { + my $cust_pkg = shift; + #my $pkgpart = $cust_pkg->pkgpart; + include( '/elements/popup_link-cust_pkg.html', + 'action' => $p. "misc/detach_pkg.html", + 'label' => emt('Detach'), + 'actionlabel' => emt('Detach'), + 'cust_pkg' => $cust_pkg, + 'width' => 616, + 'height' => 684, + ); +} + +#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..ab961b79e 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') @@ -34,26 +32,28 @@ % { <BR> <FONT SIZE=-1> - ( <%pkg_change_location_link($cust_pkg)%> ) -% if ( $cust_pkg->locationnum ) { +% unless ( $opt{no_links} ) { + ( <%pkg_change_location_link($cust_pkg)%> ) +% } +% if ( $cust_pkg->locationnum && ! $opt{no_links} ) { ( <%edit_location_link($cust_pkg->locationnum)%> ) % } </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; @@ -65,6 +65,8 @@ sub pkg_change_location_link { 'label' => emt('Change location'), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, + 'width' => 763, + 'height' => 380, ); } @@ -74,7 +76,9 @@ sub edit_location_link { 'action' => $p. "edit/cust_location.cgi?locationnum=$locationnum", 'label' => emt('Edit location'), 'actionlabel' => emt('Edit'), - ); + 'width' => 700, + 'height' => 355, + ); } </%init> diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index 5d93ad46f..7aad9a44e 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -1,7 +1,12 @@ -<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> + <% $opt{before_pkg_callback} + ? &{ $opt{before_pkg_callback} }( $cust_pkg ) + : '' + %> <A NAME="cust_pkg<% $cust_pkg->pkgnum %>" ID ="cust_pkg<% $cust_pkg->pkgnum %>" ><% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B></A> @@ -17,50 +22,54 @@ <B><% $cust_pkg->quantity %></B> </TD> </TR> -% } +% } <TR> <TD COLSPAN=2> <FONT SIZE=-1> -% unless ( $cust_pkg->get('cancel') ) { +% unless ( $cust_pkg->get('cancel') || $opt{no_links} ) { % -% my $br = 0; -% if ( $curuser->access_right('Change customer package') ) { -% $br=1; - ( <%pkg_change_link($cust_pkg)%> ) -% } +% 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 "Add comments", +% # and "Add invoice details". +% } else { +% # the usual case: links to change package definition, +% # discount, and customization +% my $br = 0; +% if ( $curuser->access_right('Change customer package') ) { +% $br=1; + ( <%pkg_change_link($cust_pkg)%> ) +% } % -% if ( $curuser->access_right('Edit customer package dates') ) { -% $br=1; - ( <%pkg_dates_link($cust_pkg)%> ) -% } +% 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; + ( <%pkg_discount_link($cust_pkg)%> ) +% } % -% 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; - ( <%pkg_discount_link($cust_pkg)%> ) -% } +% if ( $curuser->access_right('Customize customer package') ) { +% $br=1; + ( <%pkg_customize_link($cust_pkg,$part_pkg)%> ) +% } % -% if ( $curuser->access_right('Customize customer package') ) { -% $br=1; - ( <%pkg_customize_link($cust_pkg,$part_pkg)%> ) + <% $br ? '<BR>' : '' %> % } -% - <% $br ? '<BR>' : '' %> -% } -% if ( $cust_pkg->num_cust_event -% && ( $curuser->access_right('Billing event reports') -% || $curuser->access_right('View customer billing events') -% ) -% ) { - ( <%pkg_event_link($cust_pkg)%> ) -% } +% if ( $cust_pkg->num_cust_event +% && ( $curuser->access_right('Billing event reports') +% || $curuser->access_right('View customer billing events') +% ) +% ) { + ( <%pkg_event_link($cust_pkg)%> ) +% } +% } #!$supplemental </FONT> </TD> @@ -86,7 +95,7 @@ <TH BGCOLOR="#dddddd" STYLE="border-bottom: dashed 1px black; padding-bottom: 1px"> <FONT SIZE="-1"> <% mt('Invoice details') |h %> -% if ( $editi && ! $cust_pkg->get('cancel') ) { +% if ( $editi && ! $cust_pkg->get('cancel') && ! $opt{no_links} ) { (<& /elements/popup_link.html, { 'action' => $editlink. 'I', 'label' => emt('edit'), @@ -108,7 +117,7 @@ </TD> % } else { <TD> -% if ( $editi && ! $cust_pkg->get('cancel') ) { +% if ( $editi && ! $cust_pkg->get('cancel') && ! $opt{no_links} ) { <FONT SIZE="-1"> ( <% include('/elements/popup_link.html', { 'action' => $editlink. 'I', @@ -130,7 +139,7 @@ <TH BGCOLOR="#dddddd" STYLE="border-bottom: dashed 1px black; padding-bottom: 1px"> <FONT SIZE="-1"> <% mt('Comments') |h %> -% if ( $editc ) { +% if ( $editc && ! $opt{no_links} ) { (<& /elements/popup_link.html, { 'action' => $editlink. 'C', 'label' => emt('edit'), @@ -152,7 +161,7 @@ </TD> % } else { <TD> -% if ( $editc ) { +% if ( $editc && ! $opt{no_links} ) { <FONT SIZE="-1"> ( <& /elements/popup_link.html, { 'action' => $editlink. 'C', @@ -168,17 +177,45 @@ % } </TR> -% if ( $curuser->access_right('Change customer package') and -% !$cust_pkg->get('cancel') and -% !$opt{'show_location'}) { +% if ( $curuser->access_right('Change customer package') +% && ! $cust_pkg->get('cancel') +% && ! $supplemental +% && $part_pkg->freq ne '0' +% && ! $opt{no_links} +% ) +% { <TR> +% if ( FS::Conf->new->exists('invoice-unitprice') ) { <TD><FONT SIZE="-1"> - ( <% pkg_change_location_link($cust_pkg) %> ) + ( <% pkg_change_quantity_link($cust_pkg) %> ) </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 +233,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 @@ -213,6 +262,8 @@ sub pkg_change_link { 'label' => emt('Change package'), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, + 'width' => 763, + 'height' => 380, ); } @@ -226,10 +277,21 @@ sub pkg_change_location_link { 'label' => emt('Change location'), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, + 'width' => 763, + 'height' => 380, ); } -sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', emt('Edit dates'), @_ ); } +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_discount_link { my $cust_pkg = shift or return ''; diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html index 85f0c795a..82d06203b 100755 --- a/httemplate/view/cust_main/packages/section.html +++ b/httemplate/view/cust_main/packages/section.html @@ -1,53 +1,50 @@ % 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, + ( map { $_ => $opt{$_} } qw( + cust_main bgcolor + no_links before_pkg_callback before_svc_callback after_svc_callback + )), + %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 &><BR> + <& 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 +53,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 { @@ -65,6 +61,15 @@ my $show_location = $opt{'show_location'}; ( $a->getfield('pkgnum') <=> $b->getfield('pkgnum') ) } @$packages; +my %change_custnum = map { $_->change_custnum => 1 } + grep { $_->change_custnum } + grep { $_->getfield('cancel') } + @$packages; + +my $pkg_attached = ( scalar(keys %change_custnum) == 1 + && ! grep { ! $_->getfield('cancel') } @$packages + ); + my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; my %conf_opt = ( @@ -73,6 +78,7 @@ my %conf_opt = ( || $curuser->option('cust_pkg-display_times')), #for status.html 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), + 'pkg_attached' => $pkg_attached, #for status.html pkg-balances 'pkg-balances' => $conf->exists('pkg-balances'), 'money_char' => ( $conf->config('money_char') || '$' ), @@ -88,11 +94,8 @@ my %conf_opt = ( 'manage_link_text' => scalar($conf->config('svc_broadband-manage_link_text')), '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/services.html b/httemplate/view/cust_main/packages/services.html index c0a56d0f3..7dfc0049e 100644 --- a/httemplate/view/cust_main/packages/services.html +++ b/httemplate/view/cust_main/packages/services.html @@ -24,7 +24,7 @@ function clearhint_search_cust_svc(obj, str) { <TD ALIGN="right" VALIGN="top"> % my $href="${p}search/cust_pkg_svc.html?svcpart=".$part_svc->svcpart. % ";pkgnum=".$cust_pkg->pkgnum; - <A HREF="<% $href %>"><% $part_svc->svc %></A> + <A HREF="<% $href %>"><% $part_svc->svc |h %></A> </TD> <TD ALIGN="left" VALIGN="top"> <A HREF="<% $href %>"><B>(<% mt("view all [_1]", $num_cust_svc) |h %>)</B></A> @@ -74,9 +74,21 @@ function clearhint_search_cust_svc(obj, str) { <TR> <TD COLSPAN=3 ALIGN="center" STYLE="padding-bottom:4px;padding-top:0px"> - <B><% svc_provision_link($cust_pkg, $part_svc, \%opt, $curuser) %></B> + + <B> +% if ( $opt{no_links} ) { + <% $part_svc->svc |h %>: <% $part_svc->num_avail %> + <% mt('Available') |h %> +% } else { + <% svc_provision_link($cust_pkg, $part_svc, \%opt, $curuser) %> +% } + </B> + % if ( $curuser->access_right('Bulk provision customer service') -% && $part_svc->svcdb eq 'svc_phone' ) { +% && $part_svc->svcdb eq 'svc_phone' +% && ! $opt{no_links} +% ) +% { % if ( $part_svc->num_avail > 5 ) { % local $opt{'bulk'} = 1; <BR><% svc_provision_link($cust_pkg, $part_svc, \%opt, $curuser) %> diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index e9017745b..ed360cca4 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,32 +14,29 @@ <% 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_status_row_detached($cust_pkg, %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 && !$supplemental && !$cust_pkg->change_custnum ) { #? <TR> - <TD COLSPAN=<%$colspan%>> + <TD COLSPAN=<%$opt{colspan}%>> <FONT SIZE=-1> -% if ( $curuser->access_right('Un-cancel customer package') ) { +% if ( $curuser->access_right('Un-cancel customer package') && ! $opt{no_links} ) { ( <% pkg_uncancel_link($cust_pkg) %> ) % } <FONT> @@ -52,26 +51,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 +79,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') ) { - ( <% pkg_unsuspend_link($cust_pkg) %> ) - ( <% pkg_resume_link($cust_pkg) %> ) -% } -% if ( $curuser->access_right('Cancel customer package immediately') ) { - ( <% pkg_cancel_link($cust_pkg) %> ) -% } - </FONT> - </TD> - </TR> - +% if ( !$supplemental && ! $opt{no_links} ) { + <TR> + <TD COLSPAN=<%$opt{colspan}%>> + <FONT SIZE=-1> +% if ( $curuser->access_right('Unsuspend customer package') ) { + ( <% pkg_unsuspend_link($cust_pkg) %> ) + ( <% pkg_resume_link($cust_pkg) %> ) +% } +% if ( $curuser->access_right('Cancel customer package immediately') ) { + ( <% pkg_cancel_link($cust_pkg) %> ) +% } + </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 +117,9 @@ <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> +% if ( !$supplemental && ! $opt{no_links} ) { <TR> - <TD COLSPAN=<%$colspan%>> + <TD COLSPAN=<%$opt{colspan}%>> <FONT SIZE=-1> % if ( $curuser->access_right('Cancel customer package immediately') ) { ( <% pkg_cancel_link($cust_pkg) %> ) @@ -130,14 +127,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 +146,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 +168,7 @@ <% pkg_status_row_colspan( $cust_pkg, emt('Overlimit'), $billed_or_prepaid. ' '. myfreq($part_pkg), - 'color'=>'FFD000', 'colspan'=>$colspan, + 'color'=>'FFD000', %opt ) %> @@ -179,15 +177,15 @@ <% pkg_status_row_colspan( $cust_pkg, emt('Active'), $billed_or_prepaid. ' '. 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 +200,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 +210,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 && ! $opt{no_links} ) { <TR> - <TD COLSPAN=<%$colspan%>> + <TD COLSPAN=<%$opt{colspan}%>> <FONT SIZE=-1> % if ( $curuser->access_right('Suspend customer package') ) { ( <% pkg_suspend_link($cust_pkg) %> ) @@ -251,8 +249,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 +285,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 ); $html .= qq(</B></FONT>) if length($color); @@ -338,7 +356,37 @@ sub pkg_status_row_changed { '', 'size' => '-1', 'align' => 'right', - 'colspan' => $opt{'colspan'}, + ); + } + + $html; +} + +sub pkg_status_row_detached { + my( $cust_pkg, %opt ) = @_; + + return '' unless $cust_pkg->change_custnum; + + my $html = ''; + + my $cust_main = $cust_pkg->change_cust_main; + if ( $cust_main ) { + + my $cust_link = '<A HREF="cust_main.cgi?'. $cust_pkg->change_custnum. '">'. + encode_entities( $cust_main->name ). + '</A>'; + + my $what = $opt{'pkg_attached'} ? 'Attached' : 'Detached'; + + $html .= pkg_status_row_colspan( $cust_pkg, + emt("$what to customer #[_1]: ", + $cust_pkg->change_custnum + ). + $cust_link, + '', + 'size' => '-1', + 'align' => 'right', + 'colspan' => 4, ); } @@ -356,9 +404,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 +428,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 166addbf4..c7bf3748c 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,8 +72,20 @@ 'actionlabel' => emt('Enter credit'), 'width' => 616, #make room for reasons #540 default &> - <BR> +% } +% 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", + 'action' => "${p}edit/credit-cust_bill_pkg.html", + 'cust_main' => $cust_main, + 'actionlabel' => emt('Credit line items'), + 'width' => 968, #763, + 'height' => 575, + &> % } +<% $s ? '<BR>' : '' %> %# refund links @@ -127,10 +141,9 @@ %# invoice reports, combined statement % if ( $curuser->access_right('List invoices') ) { -% if ( $conf->exists('cust_main-print_statement_link') -% and $num_cust_bill > 0 ) { +% if ( $num_cust_bill > 0 ) { <A HREF="<% $p %>view/cust_main_statement-pdf.cgi?<% $custnum %>"><% - mt('Print a current statement') |h %></A> + mt('Download typeset statement PDF') |h %></A> <BR> % } <A HREF="<% $p %>search/report_cust_bill.html?custnum=<% $custnum %>"><% mt('Invoice reports') |h %></A> @@ -214,57 +227,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/^\$\-/- \$/; - - <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 ) { @@ -300,16 +276,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/^\$\-/- \$/; -% -% - +% my $showbalance = $money_char . $item->{'balance'}; +% $showbalance =~ s/^\$\-/- \$/; <TR <% $display ? $display.' ID="old_history'.$old_history++.'"' : ''%>> <TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>"> @@ -345,11 +313,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> @@ -372,14 +340,37 @@ function show_history () { } </SCRIPT> +<%def .balance_forward_row> +% my( $b, $date ) = @_; +% ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/- \$/; -<%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; @@ -487,6 +478,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) { @@ -508,6 +510,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/cust_main_statement-pdf.cgi b/httemplate/view/cust_main_statement-pdf.cgi index 7c2c20799..79110ee20 100755 --- a/httemplate/view/cust_main_statement-pdf.cgi +++ b/httemplate/view/cust_main_statement-pdf.cgi @@ -1,29 +1,34 @@ +<% $pdf %>\ <%doc> Like view/cust_statement-pdf.cgi, but for viewing/printing the implicit statement containing all of a customer's invoices. Slightly redundant. I don't see the need to create an equivalent to view/cust_statement.html for this case, but one can be added if necessary. </%doc> -<% $pdf %> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('View invoices'); -#untaint statement my($query) = $cgi->keywords; -$query =~ /^((.+)-)?(\d+)$/; -my $templatename = $2 || 'statement'; #XXX configure... via event?? eh.. -my $custnum = $3; +$query =~ /^(\d+)$/; +my $custnum = $1; +#mostly for the agent-virt, i guess. could probably bolt it onto the cust_bill +# search my $cust_main = qsearchs({ 'select' => 'cust_main.*', 'table' => 'cust_main', 'hashref' => { 'custnum' => $custnum }, 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, -}); -die "Customer #$custnum not found!" unless $cust_main; -my $cust_bill = ($cust_main->cust_bill)[-1] +}) + or die "Customer #$custnum not found!"; + +my $cust_bill = qsearchs({ + 'table' => 'cust_bill', + 'hashref' => { 'custnum' => $custnum }, + 'order_by' => 'ORDER BY _date desc LIMIT 1', +}) or die "Customer #$custnum has no invoices!"; my $cust_statement = FS::cust_statement->new({ @@ -33,11 +38,14 @@ my $cust_statement = FS::cust_statement->new({ '_date' => time, }); +my $pdf = $cust_statement->print_pdf({ + 'notice_name' => 'Statement', + 'no_date' => 1, + 'no_number' => 1, +}); -my $pdf = $cust_statement->print_pdf( '', $templatename ); - -http_header('Content-Type' => 'application/pdf' ); +http_header('Content-Type' => 'application/pdf' ); http_header('Content-Length' => length($pdf) ); -http_header('Cache-control' => 'max-age=60' ); +http_header('Cache-control' => 'max-age=60' ); </%init> diff --git a/httemplate/view/cust_pay.html b/httemplate/view/cust_pay.html index f9c8bc19c..76a24884a 100644 --- a/httemplate/view/cust_pay.html +++ b/httemplate/view/cust_pay.html @@ -77,7 +77,7 @@ <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->payby_name %> #<% $cust_pay->paymask %></B></TD> </TR> -% if ( $cust_pay->payby =~ /^(CARD|CHEK|LECB)$/ && $cust_pay->paybatch ) { +% if ( $cust_pay->payby =~ /^(CARD|CHEK|LECB)$/ && $cust_pay->processor ) { <TR> <TD ALIGN="right"><% mt('Processor') |h %></TD> @@ -86,7 +86,7 @@ <TR> <TD ALIGN="right"><% mt('Authorization #') |h %></TD> - <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->authorization %></B></TD> + <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->auth %></B></TD> </TR> % if ( $cust_pay->order_number ) { diff --git a/httemplate/view/cust_refund.html b/httemplate/view/cust_refund.html index 996b4c05a..319761506 100644 --- a/httemplate/view/cust_refund.html +++ b/httemplate/view/cust_refund.html @@ -62,7 +62,7 @@ <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->payby_name %><% $cust_refund->paymask ? ' #'.$cust_refund->paymask : '' %></B></TD> </TR> -% if ( $cust_refund->payby =~ /^(CARD|CHEK|LECB)$/ && $cust_refund->paybatch ) { +% if ( $cust_refund->payby =~ /^(CARD|CHEK|LECB)$/ && $cust_refund->processor ) { <TR> <TD ALIGN="right"><% mt('Processor') |h %></TD> @@ -71,7 +71,7 @@ <TR> <TD ALIGN="right"><% mt('Authorization #') |h %></TD> - <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->authorization %></B></TD> + <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->auth %></B></TD> </TR> % if ( $cust_refund->order_number ) { diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html index f7c685c28..02484341b 100644 --- a/httemplate/view/elements/svc_Common.html +++ b/httemplate/view/elements/svc_Common.html @@ -51,27 +51,44 @@ 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 &> +% if ( $custnum ) { +% my $url = $opt{'edit_url'} || $p. 'edit/'. $opt{'table'}. '.cgi?'; +<& /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'} +% : encode_entities($svc_x->$field); +% } % } else { % $field = $f; -% $value = $svc_x->$field; % $type = 'text'; +% $value = encode_entities($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> @@ -104,6 +121,11 @@ function areyousure(href) { <BR> +<& svc_devices.html, + 'svc_x' => $svc_x, + 'table' => $svc_x->device_table, +&> + % if ( defined($opt{'html_foot'}) ) { <% ref($opt{'html_foot'}) @@ -114,7 +136,9 @@ function areyousure(href) { % } +% if ( $cust_svc ) { <& /elements/table-tickets.html, object => $cust_svc &> +% } <% joblisting({'svcnum'=>$svcnum}, 1) %> @@ -137,7 +161,7 @@ my $fields = $opt{'fields'} my $svcnum; if ( $cgi->param('svcnum') ) { - $cgi->param('svcnum') =~ /^(\d+)$/ or die "unparsable svcnum"; + $cgi->param('svcnum') =~ /^(\d+)$/ or die "unparseable svcnum"; $svcnum = $1; } else { my($query) = $cgi->keywords; @@ -157,19 +181,29 @@ my $svc_x = qsearchs({ }) or die "Unknown svcnum $svcnum in ". $opt{'table'}. " table\n"; my $cust_svc = $svc_x->cust_svc; -my($label, $value, $svcdb) = $cust_svc->label; +my ($label, $value, $svcdb, $part_svc ); +my $labels = $opt{labels}; #not -> here -my $part_svc = $cust_svc->part_svc; +if ( $cust_svc ) { + ($label, $value, $svcdb) = $cust_svc->label; -#false laziness w/edit/svc_Common.html -#override default labels with service-definition labels if applicable -my $labels = $opt{labels}; #not -> here -foreach my $field ( keys %$labels ) { - my $col = $part_svc->part_svc_column($field); - $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\s*$/; + $part_svc = $cust_svc->part_svc; + + #false laziness w/edit/svc_Common.html + #override default labels with service-definition labels if applicable + foreach my $field ( keys %$labels ) { + my $col = $part_svc->part_svc_column($field); + $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\s*$/; + } +} else { + $label = "Unlinked $table"; + $value = $svc_x->label; + $svcdb = $table; + # just to satisfy callbacks + $part_svc = FS::part_svc->new({ svcpart => 0, svcdb => $table }); } -my $pkgnum = $cust_svc->pkgnum; +my $pkgnum = $cust_svc->pkgnum if $cust_svc; my($cust_pkg, $custnum); if ($pkgnum) { diff --git a/httemplate/view/elements/svc_devices.html b/httemplate/view/elements/svc_devices.html index d71c82f07..9458c922c 100644 --- a/httemplate/view/elements/svc_devices.html +++ b/httemplate/view/elements/svc_devices.html @@ -12,91 +12,89 @@ ) </%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' || $table eq 'cable_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> +% #$devices->can('part_device') +% if ( $table eq 'phone_device' || $svc_x->isa('FS::device_Common') ) { + <% $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' || $table eq 'cable_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->isa('FS::device_Common') ? $svc_x->device_objects() + : $table ? $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/part_event-targets.html b/httemplate/view/part_event-targets.html index 2029fd4bc..e8b1266ef 100644 --- a/httemplate/view/part_event-targets.html +++ b/httemplate/view/part_event-targets.html @@ -65,9 +65,6 @@ When event is run on <& /elements/input-date-field.html, { %} <& /elements/footer.html &> -<%once> -use List::MoreUtils qw(uniq); -</%once> <%init> my $curuser = $FS::CurrentUser::CurrentUser; 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_Common.html b/httemplate/view/svc_Common.html index 7b46dc9c9..7e300b049 100644 --- a/httemplate/view/svc_Common.html +++ b/httemplate/view/svc_Common.html @@ -7,7 +7,7 @@ # false laziness w/edit/svc_Common.html -$cgi->param('svcdb') =~ /^(svc_\w+)$/ or die "unparsable svcdb"; +$cgi->param('svcdb') =~ /^(svc_\w+)$/ or die "unparseable svcdb"; my $table = $1; require "FS/$table.pm"; 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 1cdf77615..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 &> @@ -91,15 +105,29 @@ % } +<%perl> +# minor false laziness w/ view/svc_broadband.cgi +sub slipip { + my $svc_acct = shift; + my $out = $svc_acct->slipip or return ''; + if ( $out eq '0.0.0.0' or $out eq '0e0' ) { + return '<I>('.mt('Dynamic').'</I>'; + } + $out .= ' ('. + include('/elements/popup_link-ping.html', ip => $svc_acct->slipip). + ')'; + if ( my $addr_block = $svc_acct->addr_block ) { + $out .= '<br>Netmask: ' . $addr_block->NetAddr->mask . + '<br>Gateway: ' . $addr_block->ip_gateway; + } + $out; +} +</%perl> + % if ($svc_acct->slipip) { <& /view/elements/tr.html, label=>mt('IP address'), - value=> ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' ) - ? "<I>(".mt('Dynamic').")</I>" - : $svc_acct->slipip. ' '. - include('/elements/popup_link-ping.html', - 'ip'=>$svc_acct->slipip, - ) + value=> slipip($svc_acct) &> % } 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 => \§ornum }, - { field => 'mac_addr', value => \&mac_addr }, + { field => 'ip_addr', value_callback => \&ip_addr }, + { field => 'sectornum', value_callback => \§ornum }, + { 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..ccd9ae7c7 100644 --- a/httemplate/view/svc_phone.cgi +++ b/httemplate/view/svc_phone.cgi @@ -16,19 +16,41 @@ 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 ); + +push @fields, { field => 'sms_carrierid', + #type=>'cdr_carrier', + value_callback => sub { + $_[0]->sms_carriername, + }, + }, + 'sms_account', + 'max_simultaneous', +; if ( $conf->exists('svc_phone-lnp') ) { -push @fields, 'lnp_status', - 'lnp_reject_reason', - { field => 'portable', type => 'checkbox', }, - 'lrn', - { field => 'lnp_desired_due_date', type => 'date', }, - { field => 'lnp_due_date', type => 'date', }, - 'lnp_other_provider', - 'lnp_other_provider_account'; + push @fields, 'lnp_status', + 'lnp_reject_reason', + { field => 'portable', type => 'checkbox', }, + 'lrn', + { field => 'lnp_desired_due_date', type => 'date', }, + { field => 'lnp_due_date', type => 'date', }, + 'lnp_other_provider', + 'lnp_other_provider_account', + ; } my $html_foot = sub { @@ -56,6 +78,7 @@ my $html_foot = sub { ### # Devices ### + #remove this when svc_phone isa device_Common, as elements/svc_Common will display it my $devices = include('/view/elements/svc_devices.html', 'svc_x' => $svc_phone, 'table' => 'phone_device', |
