%#this should use cust_pkg->status and cust_pkg->statuscolor eventually % 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 ) %> % } % if ( $cust_pkg->get('cancel') ) { #status: cancelled % my $cpr = $cust_pkg->last_cust_pkg_reason('cancel'); <% pkg_status_row($cust_pkg, emt('Cancelled'), 'cancel', 'color'=>'FF0000', %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'), '', %opt, ) %> % } else { <% pkg_status_row( $cust_pkg, emt('Setup'), 'setup', %opt ) %> <% 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 && !$supplemental && !$cust_pkg->change_custnum ) { #? % } % % } else { # not canceled % % if ( $cust_pkg->get('susp') ) { #suspended or on hold % % #if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) # inconsistent with FS::cust_pkg::status % if ( ! $cust_pkg->setup ) { #status: on hold <% pkg_status_row( $cust_pkg, emt('On Hold'), '', 'color'=>'7E0079', %opt ) %> % } else { #status: suspended % my ($cpr,$susplabel); % if ($cust_pkg->is_status_delay_cancel(%opt)) { % $cpr = $cust_pkg->last_cust_pkg_reason('expire'); % $susplabel = 'Suspended (Cancelled)'; % } else { % $cpr = $cust_pkg->last_cust_pkg_reason('susp'); % $susplabel = 'Suspended'; % } <% pkg_status_row( $cust_pkg, emt($susplabel), 'susp', 'color'=>'FF9900', %opt ) %> <% pkg_reason_row( $cust_pkg, $cpr, 'color' => 'FF9900', %opt ) %> % } <% pkg_status_row_noauto( $cust_pkg, %opt ) %> <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> <% pkg_status_row_discount( $cust_pkg, %opt ) %> % if ( $cust_pkg->order_date ne $cust_pkg->get('susp') ) { # not on hold % if ( $cust_pkg->get('setup') ) { <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt ) %> % } else { <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', %opt ) %> % } % } <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> <% 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) % && ! $cust_pkg->option('no_suspend_bill',1) % ) % ) % { <% pkg_status_row_if( $cust_pkg, emt('Next bill'), 'bill', %opt, curuser=>$curuser ) %> % } <% pkg_status_row_if( $cust_pkg, emt('Will resume'), 'resume', %opt, curuser=>$curuser ) %> <% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %> <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %> % # Status changes for suspended packages: can unsuspend, future-unsuspend, % # or future-change. If this package is a future change or is supplemental % # disable them all. % if ( !$supplemental && ! $opt{no_links} && !$change_from ) { % } % % } else { #status: active % % if ( $change_from ) { # future change % <% pkg_status_row_colspan( $cust_pkg, emt('Waiting for package change'), '', %opt ) %> <% pkg_status_row_if( $cust_pkg, emt('Will be activated on'), 'start_date', %opt ) %> % % } elsif ( ! $cust_pkg->get('setup') ) { # not setup % % unless ( $part_pkg->freq ) { # one-time charge <% pkg_status_row_colspan( $cust_pkg, emt('Not yet billed (one-time charge)'), '', %opt ) %> <% pkg_status_row_noauto( $cust_pkg, %opt ) %> <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row_if( $cust_pkg, ( $part_pkg->freq ? emt('Start billing') : emt('Bill on') ), 'start_date', %opt ) %> <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> % if ( !$supplemental && ! $opt{no_links} ) { % } % } else { # recurring package, not yet billed <% 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 ) %> <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> <% 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 ) %> % if ( !$opt{no_links} % and !$change_from % and !$supplemental # can be changed from its main package % and $curuser->access_right('Change package start date') ) % { % } % } % % } else { #setup % % unless ( $part_pkg->freq ) { <% 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 ) %> <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> % } else { # recurring package % % my $num_cust_svc = $cust_pkg->num_cust_svc; % my $summarize = $opt{'cust_pkg-large_pkg_size'} > 0 % && $opt{'cust_pkg-large_pkg_size'} <= $num_cust_svc; % % #overlimit process is expensive with many services, so skip w/summary % if ( !$summarize && scalar($cust_pkg->overlimit) ) { <% pkg_status_row_colspan( $cust_pkg, emt('Overlimit'), $billed_or_prepaid. ' '. myfreq($part_pkg), 'color'=>'FFD000', %opt ) %> % } else { <% pkg_status_row_colspan( $cust_pkg, emt('Active'), $billed_or_prepaid. ' '. myfreq($part_pkg), 'color'=>'00CC00', %opt ) %> % } <% pkg_status_row_noauto( $cust_pkg, %opt ) %> <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt) %> <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> % } % % } % % if ( $opt{'cust_pkg-show_autosuspend'} ) { % my $autosuspend = pkg_autosuspend_time( $cust_pkg ); % $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend; % } <% 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) %> <% pkg_status_row_if($cust_pkg, emt('Automatic suspension delayed until'), 'dundate', %opt) %> <% pkg_status_row_if( $cust_pkg, emt('Will suspend on'), 'adjourn', %opt, curuser=>$curuser ) %> <% pkg_status_row_if( $cust_pkg, emt('Will resume on'), 'resume', %opt, curuser=>$curuser ) %> <% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %> <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %> % # Status changes for active recurring packages. If it has a future % # package change scheduled, let that be modified. If it's supplemental, % # then that's the only allowed action. Otherwise allow suspend, future % # suspend, do-not-suspend, and immediate and future cancel. % if ( $part_pkg->freq and ! $opt{no_links} ) { % } % % } % }
> % if ( $curuser->access_right('Un-cancel customer package') && ! $opt{no_links} ) { ( <% pkg_uncancel_link($cust_pkg) %> ) % }
> % if ( $cust_pkg->change_to_pkgnum ) { % # then you can modify the package change % if ( $curuser->access_right('Change customer package') ) { ( <% pkg_change_now_link($cust_pkg) %> ) ( <% pkg_change_later_link($cust_pkg) %> ) ( <% pkg_unchange_link($cust_pkg) %> )
% } % } % if ( $curuser->access_right('Unsuspend customer package') ) { % if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { #on hold ( <% pkg_unhold_link($cust_pkg) %> ) % } else { ( <% pkg_unsuspend_link($cust_pkg) %> ) ( <% pkg_resume_link($cust_pkg) %> ) % } % } % if ( !$cust_pkg->change_to_pkgnum and % $curuser->access_right('Cancel customer package immediately') % ) { ( <% pkg_cancel_link($cust_pkg) %> ) % }
> % if ( $curuser->access_right('Cancel customer package immediately') ) { ( <% pkg_cancel_link($cust_pkg) %> ) % }
> ( <% pkg_change_start_link($cust_pkg) %> )
> % # action links % if ( $change_from ) { % # nothing % } elsif ( $cust_pkg->change_to_pkgnum ) { % # then you can modify the package change % if ( $curuser->access_right('Change customer package') ) { ( <% pkg_change_now_link($cust_pkg) %> ) ( <% pkg_change_later_link($cust_pkg) %> ) ( <% pkg_unchange_link($cust_pkg) %> )
% } % } % if ( !$supplemental ) { % # suspension actions--always available % if ( $curuser->access_right('Suspend customer package') ) { ( <% pkg_suspend_link($cust_pkg) %> ) % } % if ( $curuser->access_right('Suspend customer package later') ) { ( <% pkg_adjourn_link($cust_pkg) %> ) % } % if ( $curuser->access_right('Delay suspension events') ) { ( <% pkg_delay_link($cust_pkg) %> ) % } % % if ( $change_from or $cust_pkg->change_to_pkgnum ) { % # you can't cancel the package while in this state % } else { # the normal case: links to cancel the package
% if ( $curuser->access_right('Cancel customer package immediately') ) { ( <% pkg_cancel_link($cust_pkg) %> ) % } % if ( $curuser->access_right('Cancel customer package later') ) { ( <% pkg_expire_link($cust_pkg) %> ) % } % } % }
<%init> my %opt = @_; my $bgcolor = $opt{'bgcolor'}; my $cust_pkg = $opt{'cust_pkg'}; my $part_pkg = $opt{'part_pkg'}; my $curuser = $FS::CurrentUser::CurrentUser; my $width = $opt{'cust_pkg-display_times'} ? '38%' : '56%'; my $supplemental = $opt{'supplemental'}; my $change_from = $opt{'change_from'}; $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 ); unless ( $part_pkg->is_prepaid ) { $billed_or_prepaid = 'billed'; $last_bill_or_renewed = 'Last bill'; $next_bill_or_prepaid_until = 'Next bill'; } else { $billed_or_prepaid = 'prepaid'; $last_bill_or_renewed = 'Renewed'; $next_bill_or_prepaid_until = 'Prepaid until'; } #subroutines sub myfreq { my $part_pkg = shift; my $freq = $part_pkg->freq_pretty; #$freq =~ s/ / /g; $freq; } #false laziness w/package.html sub pkg_link { my($action, $label, $cust_pkg) = @_; return '' unless $cust_pkg; qq!$label!; } 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(); $html .= qq() if length($color); $html .= qq($title ); $html .= qq() if length($color); if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge $html .= ' (Balance: '. $opt{'money_char'}. $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum). ')'; } $html .= qq(); $html .= pkg_datestr($cust_pkg, $field, %opt). ''; $html; } sub pkg_status_row_if { my( $cust_pkg, $title, $field, %opt ) = @_; $title = '( '. pkg_unadjourn_link($cust_pkg). ' ) '. $title if ( $field eq 'adjourn' && $opt{curuser}->access_right('Suspend customer package later') ); $cust_pkg->get($field) ? pkg_status_row($cust_pkg, $title, $field, %opt) : ''; } sub pkg_status_row_expire { my $cust_pkg = shift; my %opt = @_; return unless $cust_pkg->get('expire'); my $title; if ( $cust_pkg->get('change_to_pkg') ) { if ( $cust_pkg->change_to_pkg->pkgpart != $cust_pkg->pkgpart ) { $title = mt('Will change to [_1] on', $cust_pkg->change_to_pkg->part_pkg->pkg); } elsif ( $cust_pkg->change_to_pkg->locationnum != $cust_pkg->locationnum ) { $title = mt('Will change location on'); } elsif (( $cust_pkg->change_to_pkg->quantity != $cust_pkg->quantity ) || ( $cust_pkg->change_to_pkg->contract_end != $cust_pkg->contract_end )) { $title = mt('Will change on'); } else { # FS::cust_pkg->change_later should have prevented this, but # just so that we can display _something_ $title = 'Unknown package change'; } } else { $title = emt('Expires'); if ( $opt{curuser}->access_right('Cancel customer package later')) { $title = '( '. pkg_unexpire_link($cust_pkg). ' ) '. $title; } } pkg_status_row( $cust_pkg, $title, 'expire', %opt ); } sub pkg_status_row_changed { my( $cust_pkg, %opt ) = @_; return '' unless $cust_pkg->change_date; my $html = pkg_status_row( $cust_pkg, emt('Package changed'), 'change_date', %opt ); my $old = $cust_pkg->old_cust_pkg; if ( $old ) { my $part_pkg = $old->part_pkg; $html .= pkg_status_row_colspan( $cust_pkg, # emt("Changed from [_1]: [_2]", # $cust_pkg->change_pkgnum, # $part_pkg->pkg_comment(cust_pkg=>$old, nopartpkg=>1) # ), '', '', 'size' => '-1', 'align' => 'right', ); } $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 = ''. encode_entities( $cust_main->name ). ''; 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, ); } $html; } sub pkg_status_row_noauto { my( $cust_pkg, %opt ) = @_; return '' unless ( $cust_pkg->no_auto || $opt{'part_pkg'}->no_auto ) && $opt{'has_cust_payby_auto'}; pkg_status_row_colspan( $cust_pkg, emt("No automatic charge"), ''); } sub pkg_status_row_separate_bill { my $cust_pkg = shift; return '' unless $cust_pkg->separate_bill; pkg_status_row_colspan( $cust_pkg, emt("Invoiced separately") ); } sub pkg_status_row_discount { my( $cust_pkg, %opt ) = @_; my $html; if ( $cust_pkg->waive_setup ) { my $label = '' . emt('Setup fee waived') . ''; $html .= pkg_status_row_colspan( $cust_pkg, $label, '', %opt ); } foreach my $cust_pkg_discount (@{ $cust_pkg->{_cust_pkg_discount_active} }) { my $discount = $cust_pkg_discount->discount; my $label = ''; if ( $cust_pkg_discount->setuprecur eq 'setup' ) { $label .= emt('Setup Discount'); } else { $label .= emt('Recurring Discount'); } $label .= ': '. $discount->description; if ( $discount->months > 0 and $cust_pkg_discount->months_used > 0 ) { my $remaining = $discount->months - $cust_pkg_discount->months_used; $remaining = sprintf('%.2f', $remaining) if $remaining =~ /\./; $label .=
. emt(" ([quant,_1,month,months] remaining)",$remaining); } $label .= '
'; #$label .= ' ('. # ''.emt('remove discount').')'; $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) = @_; my $colspan = $opt{'colspan'}; my $align = $opt{'align'} ? 'ALIGN="'. $opt{'align'}.'"' : ''; my $color = $opt{'color'} ? 'COLOR="#'.$opt{'color'}.'"' : ''; my $size = $opt{'size'} ? 'SIZE="'. $opt{'size'}. '"' : ''; my $html = qq(); $html .= qq() if length($color) || $size; $html .= qq() if $color && !$size; $html .= $title; $html .= qq() if $color && !$size; $html .= qq() if length($color) || $size; $html .= ", $addl" if length($addl); if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge $html .= ' (Balance: '. $opt{'money_char'}. $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum). ')'; } $html .= qq(); $html; } sub pkg_datestr { my($cust_pkg, $field, %opt) = @_ or return ''; return ' ' unless $cust_pkg->get($field); my $format = '%b'. ' %o,'. ' %Y'; #$format .= ' %l:%M:%S%P %z' $format .= ' %l'. ':'. '%M'. ' %P' if $opt{'cust_pkg-display_times'}; my $strip = time2str($format, $cust_pkg->get($field) ); $strip =~ s/ (\d)/$1/g; $strip; } sub pkg_suspend_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=suspend', 'label' => emt('Suspend now'), 'actionlabel' => emt('Suspend'), 'color' => '#FF9900', 'cust_pkg' => shift, 'height' => 420, ) } sub pkg_adjourn_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=adjourn', 'label' => emt('Suspend later'), 'actionlabel' => emt('Adjourn'), 'color' => '#CC6600', 'cust_pkg' => shift, 'height' => 445, ) } sub pkg_delay_link { my($cust_pkg) = shift; include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/delay_susp_pkg.html', 'label' => ( $cust_pkg->dundate ? emt('Edit suspension delay') : emt('Delay suspend') ), 'actionlabel' => emt('Delay suspend for'), 'cust_pkg' => $cust_pkg, ) } sub pkg_resume_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=resume', 'label' => emt('Unsuspend later'), 'actionlabel' => emt('Resume'), 'color' => '#00CC00', 'cust_pkg' => shift, ) } sub pkg_unhold_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/unhold_pkg.html', 'label' => emt('Start billing'), 'actionlabel' => emt('Start billing'), 'color' => '#00CC00', 'width' => 510, 'height' => 310, 'cust_pkg' => shift, ) } sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg', emt('Unsuspend now'), @_ ); } sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', emt('Abort'), @_ ); } sub pkg_unexpire_link { pkg_link('misc/unexpire_pkg', emt('Abort'), @_ ); } sub pkg_unchange_link { pkg_link('misc/do_not_change_pkg', emt('Abort change'), @_ ); } sub pkg_change_now_link { pkg_link('misc/change_pkg_now', emt('Change now'), @_ ); } sub pkg_cancel_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=cancel', 'label' => emt('Cancel now'), 'actionlabel' => emt('Cancel'), 'color' => '#ff0000', 'cust_pkg' => shift, ) } sub pkg_uncancel_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=uncancel', 'label' => emt('Un-cancel'), 'actionlabel' => emt('Un-cancel'), #'color' => #? 'cust_pkg' => shift, 'width' => 960, 'height' => 740, ) } sub pkg_expire_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'misc/cancel_pkg.html?method=expire', 'label' => emt('Cancel later'), 'actionlabel' => emt('Expire'), 'color' => '#CC0000', 'cust_pkg' => shift, ) } sub pkg_change_later_link { my $cust_pkg = shift; include( '/elements/popup_link-cust_pkg.html', 'action' => $p . 'misc/change_pkg.cgi', 'label' => emt('Reschedule'), 'actionlabel' => emt('Edit scheduled change for'), 'cust_pkg' => $cust_pkg, 'width' => 960, 'height' => 490, ) } sub pkg_change_start_link { my $cust_pkg = shift; include( '/elements/popup_link-cust_pkg.html', 'action' => $p . 'misc/change_pkg_start.html', 'label' => emt('Set start date'), 'actionlabel' => emt('Set start of billing for'), 'cust_pkg' => $cust_pkg, 'width' => 510, 'height' => 310, ) } sub svc_recharge_link { include( '/elements/popup_link-cust_svc.html', 'action' => $p. 'misc/recharge_svc.html', 'label' => emt('Recharge'), 'actionlabel' => emt('Recharge'), 'color' => '#333399', 'cust_svc' => shift, ) } sub pkg_autosuspend_time { my $cust_pkg = shift or return ''; my $days = 7; my $time = time; my $pending_suspend = 0; #this seems to be extremely inefficient... and is slowing down all customer #views while ( $days > 0 && scalar( grep { $_->part_event->action eq 'suspend' } @{$cust_pkg->cust_main->due_cust_event( time => $time + 86400*$days, testonly => 1, ) } ) ) { $pending_suspend = 1; $days--; } $pending_suspend ? time + ($days + 1) * 86400 : ''; }