1 <TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
2 <TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%">
4 %#this should use cust_pkg->status and cust_pkg->statuscolor eventually
6 % if ( $cust_pkg->order_date ) {
7 <% pkg_status_row($cust_pkg, emt('Ordered'), 'order_date', %opt ) %>
10 % if ( $cust_pkg->get('cancel') ) { #status: cancelled
11 % my $cpr = $cust_pkg->last_cust_pkg_reason('cancel');
13 <% pkg_status_row($cust_pkg, emt('Cancelled'), 'cancel', 'color'=>'FF0000', %opt ) %>
15 <% pkg_status_row_colspan( $cust_pkg,
16 ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
17 'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan,
22 % unless ( $cust_pkg->get('setup') ) {
24 <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', 'colspan'=>$colspan, %opt, ) %>
28 <% pkg_status_row( $cust_pkg, emt('Setup'), 'setup', %opt ) %>
29 <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
30 <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
31 <% pkg_status_row_if( $cust_pkg, emt('Suspended'), 'susp', %opt, curuser=>$curuser ) %>
37 % if ( $cust_pkg->get('susp') ) { #status: suspended
38 % my $cpr = $cust_pkg->last_cust_pkg_reason('susp');
40 <% pkg_status_row( $cust_pkg, emt('Suspended'), 'susp', 'color'=>'FF9900', %opt ) %>
42 <% pkg_status_row_colspan( $cust_pkg,
43 ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
44 'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan,
49 <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
51 <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
53 % unless ( $cust_pkg->get('setup') ) {
54 <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', 'colspan'=>$colspan, %opt ) %>
56 <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt ) %>
59 <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
60 <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
61 % if ( $part_pkg->option('suspend_bill', 1) ) {
62 <% pkg_status_row_if( $cust_pkg, emt('Next bill'), 'bill', %opt, curuser=>$curuser ) %>
64 <% pkg_status_row_if( $cust_pkg, emt('Expires'), 'expire', %opt, curuser=>$curuser ) %>
65 <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
68 <TD COLSPAN=<%$colspan%>>
70 % if ( $curuser->access_right('Unsuspend customer package') ) {
71 ( <% pkg_unsuspend_link($cust_pkg) %> )
73 % if ( $curuser->access_right('Cancel customer package immediately') ) {
74 ( <% pkg_cancel_link($cust_pkg) %> )
80 % } else { #status: active
82 % unless ( $cust_pkg->get('setup') ) { #not setup
84 % unless ( $part_pkg->freq ) {
86 <% pkg_status_row_colspan( $cust_pkg, emt('Not yet billed (one-time charge)'), '', 'colspan'=>$colspan, %opt ) %>
88 <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
90 <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
94 ( $part_pkg->freq ? emt('Start billing') : emt('Bill on') ),
101 <TD COLSPAN=<%$colspan%>>
103 % if ( $curuser->access_right('Cancel customer package immediately') ) {
104 ( <% pkg_cancel_link($cust_pkg) %> )
112 <% pkg_status_row_colspan($cust_pkg, emt("Not yet billed ($billed_or_prepaid [_1])", myfreq($part_pkg) ), '', 'colspan'=>$colspan, %opt ) %>
114 <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
116 <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
118 <% pkg_status_row_if($cust_pkg, emt('Start billing'), 'start_date', %opt) %>
124 % unless ( $part_pkg->freq ) {
126 <% pkg_status_row_colspan($cust_pkg, emt('One-time charge'), '', 'colspan'=>$colspan, %opt ) %>
128 <% pkg_status_row($cust_pkg, emt('Billed'), 'setup', %opt) %>
130 <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
132 <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
136 % my $num_cust_svc = $cust_pkg->num_cust_svc;
137 % my $summarize = $opt{'cust_pkg-large_pkg_size'} > 0
138 % && $opt{'cust_pkg-large_pkg_size'} <= $num_cust_svc;
140 % #overlimit process is expensive with many services, so skip w/summary
141 % if ( !$summarize && scalar($cust_pkg->overlimit) ) {
143 <% pkg_status_row_colspan( $cust_pkg,
145 $billed_or_prepaid. ' '. myfreq($part_pkg),
146 'color'=>'FFD000', 'colspan'=>$colspan,
152 <% pkg_status_row_colspan( $cust_pkg,
154 $billed_or_prepaid. ' '. myfreq($part_pkg),
155 'color'=>'00CC00', 'colspan'=>$colspan,
161 <% pkg_status_row_noauto( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
163 <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
165 <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt) %>
171 % if ( $opt{'cust_pkg-show_autosuspend'} ) {
172 % my $autosuspend = pkg_autosuspend_time( $cust_pkg );
173 % $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
176 <% pkg_status_row_changed( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
177 <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
178 <% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', %opt, curuser=>$curuser ) %>
179 <% pkg_status_row_if($cust_pkg, emt('Will automatically suspend by'), 'autosuspend', %opt) %>
180 <% pkg_status_row_if($cust_pkg, emt('Automatic suspension delayed until'), 'dundate', %opt) %>
181 <% pkg_status_row_if( $cust_pkg, emt('Will suspend on'), 'adjourn', %opt, curuser=>$curuser ) %>
182 <% pkg_status_row_if( $cust_pkg, emt('Expires'), 'expire', %opt, curuser=>$curuser ) %>
183 <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
185 % if ( $part_pkg->freq ) {
188 <TD COLSPAN=<%$colspan%>>
190 % if ( $curuser->access_right('Suspend customer package') ) {
191 ( <% pkg_suspend_link($cust_pkg) %> )
193 % if ( $curuser->access_right('Suspend customer package later') ) {
194 ( <% pkg_adjourn_link($cust_pkg) %> )
196 % if ( $curuser->access_right('Delay suspension events') ) {
197 ( <% pkg_delay_link($cust_pkg) %> )
199 % if ( $curuser->access_right('Cancel customer package immediately') ) {
200 ( <% pkg_cancel_link($cust_pkg) %> )
202 % if ( $curuser->access_right('Cancel customer package later') ) {
203 ( <% pkg_expire_link($cust_pkg) %> )
220 my $bgcolor = $opt{'bgcolor'};
221 my $cust_pkg = $opt{'cust_pkg'};
222 my $part_pkg = $opt{'part_pkg'};
223 my $curuser = $FS::CurrentUser::CurrentUser;
224 my $colspan = $opt{'cust_pkg-display_times'} ? 8 : 4;
225 my $width = $opt{'cust_pkg-display_times'} ? '38%' : '56%';
227 #false laziness w/edit/REAL_cust_pkg.cgi
228 my( $billed_or_prepaid, $last_bill_or_renewed, $next_bill_or_prepaid_until );
229 unless ( $part_pkg->is_prepaid ) {
230 $billed_or_prepaid = 'billed';
231 $last_bill_or_renewed = 'Last bill';
232 $next_bill_or_prepaid_until = 'Next bill';
234 $billed_or_prepaid = 'prepaid';
235 $last_bill_or_renewed = 'Renewed';
236 $next_bill_or_prepaid_until = 'Prepaid until';
242 my $part_pkg = shift;
243 my $freq = $part_pkg->freq_pretty;
244 #$freq =~ s/ / /g;
248 #false laziness w/package.html
250 my($action, $label, $cust_pkg) = @_;
251 return '' unless $cust_pkg;
252 qq!<a href="$p$action.cgi?!. $cust_pkg->pkgnum. qq!">$label</a>!;
256 my( $cust_pkg, $title, $field, %opt ) = @_;
258 my $color = $opt{'color'};
260 my $html = qq(<TR><TD WIDTH="<%$width%>" ALIGN="right">);
261 $html .= qq(<FONT COLOR="#$color"><B>) if length($color);
262 $html .= qq($title );
263 $html .= qq(</B></FONT>) if length($color);
265 if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
266 $html .= ' (Balance: <B>'. $opt{'money_char'}.
267 $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
272 $html .= pkg_datestr($cust_pkg, $field, %opt). '</TR>';
277 sub pkg_status_row_if {
278 my( $cust_pkg, $title, $field, %opt ) = @_;
280 $title = '<FONT SIZE=-1>( '. pkg_unadjourn_link($cust_pkg). ' ) </FONT>'. $title
281 if ( $field eq 'adjourn' &&
282 $opt{curuser}->access_right('Suspend customer package later')
285 $title = '<FONT SIZE=-1>( '. pkg_unexpire_link($cust_pkg). ' ) </FONT>'. $title
286 if ( $field eq 'expire' &&
287 $opt{curuser}->access_right('Cancel customer package later')
290 $cust_pkg->get($field) ? pkg_status_row($cust_pkg, $title, $field, %opt) : '';
293 sub pkg_status_row_changed {
294 my( $cust_pkg, %opt ) = @_;
296 return '' unless $cust_pkg->change_date;
299 pkg_status_row( $cust_pkg, emt('Package changed'), 'change_date', %opt );
301 my $old = $cust_pkg->old_cust_pkg;
303 my $part_pkg = $old->part_pkg;
304 $html .= pkg_status_row_colspan( $cust_pkg,
305 emt("Changed from [_1]: [_2]",
306 $cust_pkg->change_pkgnum,
307 $part_pkg->pkg_comment(nopartpkg => 1) ),
311 'colspan' => $opt{'colspan'},
318 sub pkg_status_row_noauto {
319 my( $cust_pkg, %opt ) = @_;
320 my $part_pkg = $opt{'part_pkg'};
321 return '' unless $cust_pkg->no_auto || $part_pkg->no_auto;
323 #inefficient, should be passed in
324 my $cust_main = $cust_pkg->cust_main;
326 return '' unless $cust_main->payby =~ /^(CARD|CHEK)$/;
327 my $what = lc(FS::payby->shortname($cust_main->payby));
329 pkg_status_row_colspan( $cust_pkg, emt("No automatic $what charge"), '',
330 'colspan' => $opt{'colspan'},
334 sub pkg_status_row_discount {
335 my( $cust_pkg, %opt ) = @_;
339 foreach my $cust_pkg_discount ( $cust_pkg->cust_pkg_discount_active ) {
341 my $discount = $cust_pkg_discount->discount;
343 my $label = '<B>'.emt('Discount').'</B>: '. $discount->description;
344 if ( $discount->months ) {
345 my $remaining = $discount->months - $cust_pkg_discount->months_used;
346 $remaining = sprintf('%.2f', $remaining) if $remaining =~ /\./;
347 $label .= emt("([_1] months remaining)",$remaining);
350 $label .= ' <FONT SIZE="-1">('.
351 '<A HREF="../misc/delete-cust_pkg_discount.html?'.
352 $cust_pkg_discount->pkgdiscountnum.
353 '">'.emt('remove discount').'</A>)</FONT>';
355 $html .= pkg_status_row_colspan( $cust_pkg, $label, '',
356 'colspan' => $opt{'colspan'},
364 sub pkg_status_row_colspan {
365 my($cust_pkg, $title, $addl, %opt) = @_;
367 my $colspan = $opt{'colspan'};
369 my $align = $opt{'align'} ? 'ALIGN="'. $opt{'align'}.'"' : '';
370 my $color = $opt{'color'} ? 'COLOR="#'.$opt{'color'}.'"' : '';
371 my $size = $opt{'size'} ? 'SIZE="'. $opt{'size'}. '"' : '';
373 my $html = qq(<TR><TD COLSPAN=$colspan $align>);
374 $html .= qq(<FONT $color $size>) if length($color) || $size;
375 $html .= qq(<B>) if $color && !$size;
377 $html .= qq(</B>) if $color && !$size;
378 $html .= qq(</FONT>) if length($color) || $size;
379 $html .= ", $addl" if length($addl);
381 if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
382 $html .= ' (Balance: <B>'. $opt{'money_char'}.
383 $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
387 $html .= qq(</TD></TR>);
394 my($cust_pkg, $field, %opt) = @_ or return '';
395 return ' ' unless $cust_pkg->get($field);
396 my $format = '<TD align="left"><B>%b</B></TD>'.
397 '<TD align="right"><B> %o,</B></TD>'.
398 '<TD align="right"><B> %Y</B></TD>';
399 #$format .= ' <FONT SIZE=-3>%l:%M:%S%P %z</FONT>'
400 $format .= '<TD ALIGN="right"><B> %l</TD>'.
401 '<TD ALIGN="center"><B>:</B></TD>'.
402 '<TD ALIGN="left"><B>%M</B></TD>'.
403 '<TD ALIGN="left"><B> %P</B></TD>'
404 if $opt{'cust_pkg-display_times'};
405 my $strip = time2str($format, $cust_pkg->get($field) );
406 $strip =~ s/ (\d)/$1/g;
410 sub pkg_suspend_link {
411 include( '/elements/popup_link-cust_pkg.html',
412 'action' => $p. 'misc/cancel_pkg.html?method=suspend',
413 'label' => emt('Suspend now'),
414 'actionlabel' => emt('Suspend'),
415 'color' => '#FF9900',
420 sub pkg_adjourn_link {
421 include( '/elements/popup_link-cust_pkg.html',
422 'action' => $p. 'misc/cancel_pkg.html?method=adjourn',
423 'label' => emt('Suspend later'),
424 'actionlabel' => emt('Adjourn'),
425 'color' => '#CC6600',
431 my($cust_pkg) = shift;
432 include( '/elements/popup_link-cust_pkg.html',
433 'action' => $p. 'misc/delay_susp_pkg.html',
434 'label' => ( $cust_pkg->dundate
435 ? emt('Edit suspension delay')
436 : emt('Delay suspend')
438 'actionlabel' => emt('Delay suspend for'),
439 'cust_pkg' => $cust_pkg,
443 sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg', emt('Unsuspend'), @_ ); }
444 sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', emt('Abort'), @_ ); }
445 sub pkg_unexpire_link { pkg_link('misc/unexpire_pkg', emt('Abort'), @_ ); }
447 sub pkg_cancel_link {
448 include( '/elements/popup_link-cust_pkg.html',
449 'action' => $p. 'misc/cancel_pkg.html?method=cancel',
450 'label' => emt('Cancel now'),
451 'actionlabel' => emt('Cancel'),
452 'color' => '#ff0000',
457 sub pkg_expire_link {
458 include( '/elements/popup_link-cust_pkg.html',
459 'action' => $p. 'misc/cancel_pkg.html?method=expire',
460 'label' => emt('Cancel later'),
461 'actionlabel' => emt('Expire'),
462 'color' => '#CC0000',
467 sub svc_recharge_link {
468 include( '/elements/popup_link-cust_svc.html',
469 'action' => $p. 'misc/recharge_svc.html',
470 'label' => emt('Recharge'),
471 'actionlabel' => emt('Recharge'),
472 'color' => '#333399',
477 sub pkg_autosuspend_time {
478 my $cust_pkg = shift or return '';
481 my $pending_suspend = 0;
482 #this seems to be extremely inefficient... and is slowing down all customer
486 grep { $_->part_event->action eq 'suspend' }
487 @{$cust_pkg->cust_main->due_cust_event( time => $time + 86400*$days,
493 $pending_suspend = 1;
497 $pending_suspend ? time + ($days + 1) * 86400 : '';