optimize package list with lots of packages, RT#28526
[freeside.git] / httemplate / view / cust_main / packages / status.html
1 <TD CLASS="inv" BGCOLOR="<% $bgcolor %>" VALIGN="top">
2   <TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%">
3
4 %#this should use cust_pkg->status and cust_pkg->statuscolor eventually
5
6 % if ( $supplemental ) {
7     <% pkg_status_row_colspan($cust_pkg, emt('Supplemental'), '', 'color' => '7777FF', %opt) %>
8 % } elsif ( $cust_pkg->order_date ) {
9     <% pkg_status_row($cust_pkg, emt('Ordered'), 'order_date', %opt ) %>
10 % }
11
12 % if ( $cust_pkg->get('cancel') ) { #status: cancelled
13 %   my $cpr = $cust_pkg->last_cust_pkg_reason('cancel');
14
15     <% pkg_status_row($cust_pkg, emt('Cancelled'), 'cancel', 'color'=>'FF0000', %opt ) %>
16
17     <% pkg_status_row_detached($cust_pkg, %opt) %>
18
19     <% pkg_reason_row($cust_pkg, $cpr, color => 'ff0000', %opt) %>
20
21 %   unless ( $cust_pkg->get('setup') ) { 
22
23         <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', %opt, ) %>
24
25 %   } else { 
26
27        <% pkg_status_row( $cust_pkg, emt('Setup'), 'setup', %opt ) %>
28        <% pkg_status_row_changed( $cust_pkg, %opt ) %>
29        <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
30        <% pkg_status_row_if( $cust_pkg, emt('Suspended'), 'susp', %opt, curuser=>$curuser ) %>
31
32 %   } 
33 %
34 %   if ( $part_pkg->freq && !$supplemental && !$cust_pkg->change_custnum ) { #?
35
36       <TR>
37         <TD COLSPAN=<%$opt{colspan}%>>
38           <FONT SIZE=-1>
39 %           if ( $curuser->access_right('Un-cancel customer package') && ! $opt{no_links} ) { 
40               (&nbsp;<% pkg_uncancel_link($cust_pkg) %>&nbsp;)
41 %           } 
42           <FONT>
43         </TD>
44       </TR>
45 %   }
46 %
47 % } else {
48 %
49 %   if ( $cust_pkg->get('susp') ) { #suspended or on hold
50 %
51 %     if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { #status: on hold
52
53         <% pkg_status_row( $cust_pkg, emt('On Hold'), '', 'color'=>'7E0079', %opt ) %>
54
55 %     } else { #status: suspended
56
57         <% pkg_status_row( $cust_pkg, emt('Suspended'), 'susp', 'color'=>'FF9900', %opt ) %>
58 %       my $cpr = $cust_pkg->last_cust_pkg_reason('susp');
59         <% pkg_reason_row( $cust_pkg, $cpr, 'color' => 'FF9900', %opt ) %>
60
61 %     }
62
63     <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
64
65     <% pkg_status_row_discount( $cust_pkg, %opt ) %>
66
67 %   unless ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { #on hold
68 %     unless ( $cust_pkg->get('setup') ) { 
69         <% pkg_status_row_colspan( $cust_pkg, emt('Never billed'), '', %opt ) %>
70 %     } else { 
71         <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt ) %>
72 %     }
73 %   } 
74
75     <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
76
77     <% pkg_status_row_changed( $cust_pkg, %opt ) %>
78     <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
79 %   if ( $cust_pkg->option('suspend_bill', 1)
80 %        || ( $part_pkg->option('suspend_bill', 1)
81 %               && ! $cust_pkg->option('no_suspend_bill',1)
82 %           )
83 %      )
84 %   {
85       <% pkg_status_row_if( $cust_pkg, emt('Next bill'), 'bill', %opt, curuser=>$curuser ) %>
86 %   }
87     <% pkg_status_row_if( $cust_pkg, emt('Will resume'), 'resume', %opt, curuser=>$curuser ) %>
88     <% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %>
89     <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
90
91 % if ( !$supplemental && ! $opt{no_links} && !$change_from ) {
92       <TR>
93         <TD COLSPAN=<%$opt{colspan}%>>
94           <FONT SIZE=-1>
95 %           if ( $cust_pkg->change_to_pkgnum ) {
96 %               # then you can modify the package change
97 %               if ( $curuser->access_right('Change customer package') ) {
98                 (&nbsp;<% pkg_change_now_link($cust_pkg) %>&nbsp;)
99                 (&nbsp;<% pkg_change_later_link($cust_pkg) %>&nbsp;)
100                 (&nbsp;<% pkg_unchange_link($cust_pkg) %>&nbsp;)
101                 <BR>
102 %               }
103 %           }
104 %           if ( $curuser->access_right('Unsuspend customer package') ) { 
105 %             if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { #on hold
106                 (&nbsp;<% pkg_link('misc/unsusp_pkg', emt('Start bililng now'), $cust_pkg) %>&nbsp;)
107 %             } else {
108                 (&nbsp;<% pkg_unsuspend_link($cust_pkg) %>&nbsp;)
109                 (&nbsp;<% pkg_resume_link($cust_pkg) %>&nbsp;)
110 %             }
111 %           }
112 %           if ( !$cust_pkg->change_to_pkgnum and
113 %                $curuser->access_right('Cancel customer package immediately')
114 %           ) {
115               (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
116 %           } 
117           </FONT>
118         </TD>
119       </TR>
120 %     }
121 %
122 %   } else { #status: active
123 %
124 %     if ( $change_from ) { # future change
125 %
126           <% pkg_status_row_colspan( $cust_pkg, emt('Waiting for package change'), '', %opt ) %>
127           <% pkg_status_row( $cust_pkg,
128                              emt('Will be activated on'),
129                              'start_date',
130                              %opt ) %>
131 %
132 %     } elsif ( ! $cust_pkg->get('setup') ) { # not setup
133 %
134 %       unless ( $part_pkg->freq ) { # one-time charge
135
136           <% pkg_status_row_colspan( $cust_pkg, emt('Not yet billed (one-time charge)'), '', %opt ) %>
137
138           <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
139
140           <% pkg_status_row_discount( $cust_pkg, %opt ) %>
141
142           <% pkg_status_row_if(
143                $cust_pkg,
144                ( $part_pkg->freq ? emt('Start billing') : emt('Bill on') ),
145                'start_date',
146                %opt
147              )
148           %>
149
150           <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
151
152 %         if ( !$supplemental && ! $opt{no_links} ) {
153           <TR>
154             <TD COLSPAN=<%$opt{colspan}%>>
155               <FONT SIZE=-1>
156 %               if ( $curuser->access_right('Cancel customer package immediately') ) { 
157                   (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
158 %               } 
159               </FONT>
160             </TD>
161           </TR>
162 %         }
163
164 %       } else { 
165
166           <% pkg_status_row_colspan($cust_pkg, emt("Not yet billed ($billed_or_prepaid [_1])", myfreq($part_pkg) ), '', %opt ) %>
167
168           <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
169
170           <% pkg_status_row_discount( $cust_pkg, %opt ) %>
171
172           <% pkg_status_row_if($cust_pkg, emt('Start billing'), 'start_date', %opt) %>
173           <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
174
175 %       } 
176 %
177 %     } else { #setup
178 %
179 %       unless ( $part_pkg->freq ) { 
180
181           <% pkg_status_row_colspan($cust_pkg, emt('One-time charge'), '', %opt ) %>
182
183           <% pkg_status_row($cust_pkg, emt('Billed'), 'setup', %opt) %>
184
185           <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
186
187           <% pkg_status_row_discount( $cust_pkg, %opt ) %>
188
189           <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
190
191 %       } else { 
192 %
193 %         my $num_cust_svc = $cust_pkg->num_cust_svc;
194 %         my $summarize = $opt{'cust_pkg-large_pkg_size'} > 0
195 %                           && $opt{'cust_pkg-large_pkg_size'} <= $num_cust_svc;
196 %
197 %         #overlimit process is expensive with many services, so skip w/summary
198 %         if ( !$summarize && scalar($cust_pkg->overlimit) ) {
199
200             <% pkg_status_row_colspan( $cust_pkg,
201                  emt('Overlimit'),
202                  $billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
203                  'color'=>'FFD000',
204                  %opt
205                )
206             %>
207
208 %         } else {
209             <% pkg_status_row_colspan( $cust_pkg,
210                  emt('Active'),
211                  $billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
212                  'color'=>'00CC00',
213                  %opt
214                )
215             %>
216 %         } 
217
218           <% pkg_status_row_noauto( $cust_pkg, %opt ) %>
219
220           <% pkg_status_row_discount( $cust_pkg, %opt ) %>
221
222           <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt) %>
223
224           <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
225
226 %       } 
227 %
228 %     }
229 %
230 %     if ( $opt{'cust_pkg-show_autosuspend'} ) {
231 %       my $autosuspend = pkg_autosuspend_time( $cust_pkg );
232 %       $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
233 %     }
234
235       <% pkg_status_row_changed( $cust_pkg, %opt ) %>
236       <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', %opt, curuser=>$curuser ) %>
237       <% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', %opt, curuser=>$curuser ) %>
238       <% pkg_status_row_if($cust_pkg, emt('Will automatically suspend by'), 'autosuspend', %opt) %>
239       <% pkg_status_row_if($cust_pkg, emt('Automatic suspension delayed until'), 'dundate', %opt) %>
240       <% pkg_status_row_if( $cust_pkg, emt('Will suspend on'), 'adjourn', %opt, curuser=>$curuser ) %>
241       <% pkg_status_row_if( $cust_pkg, emt('Will resume on'), 'resume', %opt, curuser=>$curuser ) %>
242       <% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %>
243       <% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
244
245 %     if ( $part_pkg->freq and !$supplemental && ! $opt{no_links} ) { 
246
247         <TR>
248           <TD COLSPAN=<%$opt{colspan}%>>
249             <FONT SIZE=-1>
250 % # action links
251 %           if ( $change_from ) {
252 %               # nothing
253 %           } elsif ( $cust_pkg->change_to_pkgnum ) {
254 %               # then you can modify the package change
255 %               if ( $curuser->access_right('Change customer package') ) {
256                 (&nbsp;<% pkg_change_now_link($cust_pkg) %>&nbsp;)
257                 (&nbsp;<% pkg_change_later_link($cust_pkg) %>&nbsp;)
258                 (&nbsp;<% pkg_unchange_link($cust_pkg) %>&nbsp;)
259                 <BR>
260 %               }
261 %           }
262
263 %           # suspension actions--always available
264 %           if ( $curuser->access_right('Suspend customer package') ) { 
265               (&nbsp;<% pkg_suspend_link($cust_pkg) %>&nbsp;)
266 %           } 
267 %           if ( $curuser->access_right('Suspend customer package later') ) { 
268               (&nbsp;<% pkg_adjourn_link($cust_pkg) %>&nbsp;)
269 %           } 
270 %           if ( $curuser->access_right('Delay suspension events') ) { 
271               (&nbsp;<% pkg_delay_link($cust_pkg) %>&nbsp;)
272 %           }
273 %
274 %           if ( $change_from or $cust_pkg->change_to_pkgnum ) {
275 %               # you can't cancel the package while in this state
276 %           } else { # the normal case: links to cancel the package
277               <BR>
278 %             if ( $curuser->access_right('Cancel customer package immediately') ) { 
279                 (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
280 %             }
281 %             if ( $curuser->access_right('Cancel customer package later') ) { 
282                 (&nbsp;<% pkg_expire_link($cust_pkg) %>&nbsp;)
283 %             } 
284 %           }
285
286             <FONT>
287           </TD>
288         </TR>
289 %     }
290 %
291 %   } 
292 % } 
293
294   </TABLE>
295 </TD>
296 <%init>
297
298 my %opt = @_;
299
300 my $bgcolor  = $opt{'bgcolor'};
301 my $cust_pkg = $opt{'cust_pkg'};
302 my $part_pkg = $opt{'part_pkg'};
303 my $curuser  = $FS::CurrentUser::CurrentUser;
304 my $width    = $opt{'cust_pkg-display_times'} ? '38%' : '56%';
305 my $supplemental = $opt{'supplemental'};
306 my $change_from  = $opt{'change_from'};
307
308 $opt{colspan}  = $opt{'cust_pkg-display_times'} ? 8 : 4;
309
310 #false laziness w/edit/REAL_cust_pkg.cgi
311 my( $billed_or_prepaid, $last_bill_or_renewed, $next_bill_or_prepaid_until );
312 unless ( $part_pkg->is_prepaid ) {
313   $billed_or_prepaid = 'billed';
314   $last_bill_or_renewed = 'Last&nbsp;bill';
315   $next_bill_or_prepaid_until = 'Next&nbsp;bill';
316 } else {
317   $billed_or_prepaid = 'prepaid';
318   $last_bill_or_renewed = 'Renewed';
319   $next_bill_or_prepaid_until = 'Prepaid&nbsp;until';
320 }
321
322 #subroutines
323
324 sub myfreq {
325   my $part_pkg = shift;
326   my $freq = $part_pkg->freq_pretty;
327   #$freq =~ s/ /&nbsp;/g;
328   $freq;
329 }
330
331 #false laziness w/package.html
332 sub pkg_link {
333   my($action, $label, $cust_pkg) = @_;
334   return '' unless $cust_pkg;
335   qq!<a href="$p$action.cgi?!. $cust_pkg->pkgnum. qq!">$label</a>!;
336 }
337
338 sub pkg_status_row {
339   my( $cust_pkg, $title, $field, %opt ) = @_;
340
341   if ( $field and $cust_pkg->main_pkgnum ) {
342     # for supplemental packages, we mostly only show these if they're 
343     # different from the main package
344     my $main_pkg = $cust_pkg-> main_pkg;
345     if (    $main_pkg->get($field) ne $cust_pkg->get($field)
346         # with some exceptions
347         or  $field eq 'bill'
348         or  $field eq 'last_bill'
349         or  $field eq 'setup'
350         or  $field eq 'susp'
351         or  $field eq 'cancel'
352       ) {
353       # handle it normally
354     } else {
355       return '';
356     }
357   }
358
359   my $color = $opt{'color'};
360
361   my $html = qq(<TR><TD WIDTH="$width" ALIGN="right">);
362   $html   .= qq(<FONT COLOR="#$color"><B>) if length($color);
363   $html   .= qq($title&nbsp;);
364   $html   .= qq(</B></FONT>) if length($color);
365
366   if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
367     $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
368              $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
369              '</B>)';
370   }
371
372   $html   .= qq(</TD>);
373   $html   .= pkg_datestr($cust_pkg, $field, %opt). '</TR>';
374
375   $html;
376 }
377
378 sub pkg_status_row_if {
379   my( $cust_pkg, $title, $field, %opt ) = @_;
380   
381   $title = '<FONT SIZE=-1>(&nbsp;'. pkg_unadjourn_link($cust_pkg). '&nbsp;)&nbsp;</FONT>'. $title
382     if ( $field eq 'adjourn' &&
383          $opt{curuser}->access_right('Suspend customer package later')
384        );
385
386   $cust_pkg->get($field) ? pkg_status_row($cust_pkg, $title, $field, %opt) : '';
387 }
388
389 sub pkg_status_row_expire {
390   my $cust_pkg = shift;
391   my %opt = @_;
392   return unless $cust_pkg->get('expire');
393
394   my $title;
395
396   if ( $cust_pkg->get('change_to_pkg') ) {
397     if ( $cust_pkg->change_to_pkg->pkgpart != $cust_pkg->pkgpart ) {
398       $title = mt('Will change to <b>[_1]</b> on',
399                  $cust_pkg->change_to_pkg->part_pkg->pkg);
400     } elsif ( $cust_pkg->change_to_pkg->locationnum != $cust_pkg->locationnum )
401     {
402       $title = mt('Will <b>change location</b> on');
403     } else {
404       # FS::cust_pkg->change_later should have prevented this, but 
405       # just so that we can display _something_
406       $title = '<font color="#ff0000">Unknown package change</font>';
407     }
408
409   } else {
410
411     $title = emt('Expires');
412     if ( $opt{curuser}->access_right('Cancel customer package later')) {
413       $title = '<FONT SIZE=-1>(&nbsp;'. pkg_unexpire_link($cust_pkg). '&nbsp;)&nbsp;</FONT>'. $title;
414     }
415
416   }
417
418   pkg_status_row( $cust_pkg, $title, 'expire', %opt );
419 }
420
421 sub pkg_status_row_changed {
422   my( $cust_pkg, %opt ) = @_;
423
424   return '' unless $cust_pkg->change_date;
425
426   my $html =
427     pkg_status_row( $cust_pkg, emt('Package changed'), 'change_date', %opt );
428
429   my $old = $cust_pkg->old_cust_pkg;
430   if ( $old ) {
431     my $part_pkg = $old->part_pkg;
432     $html .= pkg_status_row_colspan(
433       $cust_pkg, 
434       emt("Changed from [_1]: [_2]",
435              $cust_pkg->change_pkgnum,
436              $part_pkg->pkg_comment(cust_pkg=>$old, nopartpkg=>1)
437          ),
438       '',
439       'size'    => '-1',
440       'align'   => 'right',
441     );
442   }
443
444   $html;
445 }
446
447 sub pkg_status_row_detached {
448   my( $cust_pkg, %opt ) = @_;
449
450   return '' unless $cust_pkg->change_custnum;
451
452   my $html = '';
453
454   my $cust_main = $cust_pkg->change_cust_main;
455   if ( $cust_main ) {
456
457     my $cust_link = '<A HREF="cust_main.cgi?'.  $cust_pkg->change_custnum. '">'.
458                       encode_entities( $cust_main->name ).
459                     '</A>';
460
461     my $what = $opt{'pkg_attached'} ? 'Attached' : 'Detached';
462
463     $html .= pkg_status_row_colspan( $cust_pkg, 
464                                      emt("$what to customer #[_1]: ",
465                                             $cust_pkg->change_custnum
466                                         ).
467                                        $cust_link,
468                                      '',
469                                      'size'    => '-1',
470                                      'align'   => 'right',
471                                      'colspan' => 4,
472                                    );
473   }
474
475   $html;
476 }
477
478 sub pkg_status_row_noauto {
479   my( $cust_pkg, %opt ) = @_;
480   my $part_pkg = $opt{'part_pkg'};
481   return '' unless $cust_pkg->no_auto || $part_pkg->no_auto;
482
483   #inefficient, should be passed in
484   my $cust_main = $cust_pkg->cust_main;
485
486   return '' unless $cust_main->payby =~ /^(CARD|CHEK)$/;
487   my $what = lc(FS::payby->shortname($cust_main->payby));
488
489   pkg_status_row_colspan( $cust_pkg, emt("No automatic $what charge"), '');
490 }
491
492 sub pkg_status_row_discount {
493   my( $cust_pkg, %opt ) = @_;
494
495   my $html;
496
497   foreach my $cust_pkg_discount (@{ $cust_pkg->{_cust_pkg_discount_active} }) {
498
499     my $discount = $cust_pkg_discount->discount;
500
501     my $label = '<B>'.emt('Discount').'</B>: '. $discount->description;
502     if ( $discount->months ) {
503       my $remaining = $discount->months - $cust_pkg_discount->months_used;
504       $remaining = sprintf('%.2f', $remaining) if $remaining =~ /\./;
505       $label .= emt("([_1] months remaining)",$remaining);
506     }
507
508     $label .= ' <FONT SIZE="-1">('.
509                 '<A HREF="../misc/delete-cust_pkg_discount.html?'.
510                   $cust_pkg_discount->pkgdiscountnum.
511                 '">'.emt('remove discount').'</A>)</FONT>';
512
513     $html .= pkg_status_row_colspan( $cust_pkg, $label, '', %opt );
514
515   }
516
517   $html;
518 }
519
520 sub pkg_reason_row {
521   my ($cust_pkg, $cpr, %opt) = @_;
522   return '' if $cust_pkg->main_pkgnum;
523
524   my $reasontext = '';
525   $reasontext = $cpr->reasontext . ' by ' . $cpr->otaker if $cpr;
526   pkg_status_row_colspan( $cust_pkg, $reasontext, '',
527     'align'=>'right', 'size'=>'-2', %opt
528   );
529 }
530
531 sub pkg_status_row_colspan {
532   my($cust_pkg, $title, $addl, %opt) = @_;
533
534   my $colspan  = $opt{'colspan'};
535
536   my $align = $opt{'align'} ? 'ALIGN="'. $opt{'align'}.'"' : '';
537   my $color = $opt{'color'} ? 'COLOR="#'.$opt{'color'}.'"' : '';
538   my $size  = $opt{'size'}  ? 'SIZE="'.  $opt{'size'}. '"' : '';
539
540   my $html = qq(<TR><TD COLSPAN=$colspan $align>);
541   $html   .= qq(<FONT $color $size>) if length($color) || $size;
542   $html   .= qq(<B>) if $color && !$size;
543   $html   .= $title;
544   $html   .= qq(</B>) if $color && !$size;
545   $html   .= qq(</FONT>) if length($color) || $size;
546   $html   .= ",&nbsp;$addl" if length($addl);
547
548   if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
549     $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
550              $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
551              '</B>)';
552   }
553
554   $html   .= qq(</TD></TR>);
555
556   $html;
557
558 }
559
560 sub pkg_datestr {
561   my($cust_pkg, $field, %opt) = @_ or return '';
562   return '&nbsp;' unless $cust_pkg->get($field);
563   my $format = '<TD align="left"><B>%b</B></TD>'.
564                '<TD align="right"><B>&nbsp;%o,</B></TD>'.
565                '<TD align="right"><B>&nbsp;%Y</B></TD>';
566   #$format .= '&nbsp;<FONT SIZE=-3>%l:%M:%S%P&nbsp;%z</FONT>'
567   $format .= '<TD ALIGN="right"><B>&nbsp;%l</TD>'.
568              '<TD ALIGN="center"><B>:</B></TD>'.
569              '<TD ALIGN="left"><B>%M</B></TD>'.
570              '<TD ALIGN="left"><B>&nbsp;%P</B></TD>'
571     if $opt{'cust_pkg-display_times'};
572   my $strip = time2str($format, $cust_pkg->get($field) );
573   $strip =~ s/ (\d)/$1/g;
574   $strip;
575 }
576
577 sub pkg_suspend_link {
578   include( '/elements/popup_link-cust_pkg.html',
579              'action'      => $p. 'misc/cancel_pkg.html?method=suspend',
580              'label'       => emt('Suspend now'),
581              'actionlabel' => emt('Suspend'),
582              'color'       => '#FF9900',
583              'cust_pkg'    => shift,
584          )
585 }
586
587 sub pkg_adjourn_link {
588   include( '/elements/popup_link-cust_pkg.html',
589              'action'      => $p. 'misc/cancel_pkg.html?method=adjourn',
590              'label'       => emt('Suspend later'),
591              'actionlabel' => emt('Adjourn'),
592              'color'       => '#CC6600',
593              'cust_pkg'    => shift,
594          )
595 }
596
597 sub pkg_delay_link  {
598   my($cust_pkg) = shift;
599   include( '/elements/popup_link-cust_pkg.html',
600              'action'      => $p. 'misc/delay_susp_pkg.html',
601              'label'       => ( $cust_pkg->dundate
602                                   ? emt('Edit suspension delay')
603                                   : emt('Delay suspend')
604                               ),
605              'actionlabel' => emt('Delay suspend for'),
606              'cust_pkg'    => $cust_pkg,
607          )
608 }
609
610 sub pkg_resume_link {
611   include( '/elements/popup_link-cust_pkg.html',
612              'action'      => $p. 'misc/cancel_pkg.html?method=resume',
613              'label'       => emt('Unsuspend later'),
614              'actionlabel' => emt('Resume'),
615              'color'       => '#00CC00',
616              'cust_pkg'    => shift,
617          )
618 }
619
620 sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg',    emt('Unsuspend now'), @_ ); }
621 sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', emt('Abort'),     @_ ); }
622 sub pkg_unexpire_link  { pkg_link('misc/unexpire_pkg',  emt('Abort'),     @_ ); }
623 sub pkg_unchange_link  { pkg_link('misc/do_not_change_pkg',  emt('Abort change'),     @_ ); }
624 sub pkg_change_now_link  { pkg_link('misc/change_pkg_now',  emt('Change now'),     @_ ); }
625
626 sub pkg_cancel_link {
627   include( '/elements/popup_link-cust_pkg.html',
628              'action'      => $p. 'misc/cancel_pkg.html?method=cancel',
629              'label'       => emt('Cancel now'),
630              'actionlabel' => emt('Cancel'),
631              'color'       => '#ff0000',
632              'cust_pkg'    => shift,
633          )
634 }
635
636 sub pkg_uncancel_link {
637   include( '/elements/popup_link-cust_pkg.html',
638              'action'      => $p. 'misc/cancel_pkg.html?method=uncancel',
639              'label'       => emt('Un-cancel'),
640              'actionlabel' => emt('Un-cancel'),
641              #'color'       =>  #?
642              'cust_pkg'    => shift,
643          )
644 }
645
646 sub pkg_expire_link {
647   include( '/elements/popup_link-cust_pkg.html',
648              'action'      => $p. 'misc/cancel_pkg.html?method=expire',
649              'label'       => emt('Cancel later'),
650              'actionlabel' => emt('Expire'),
651              'color'       => '#CC0000',
652              'cust_pkg'    => shift,
653          )
654 }
655
656 sub pkg_change_later_link {
657   my $cust_pkg = shift;
658   include( '/elements/popup_link-cust_pkg.html',
659     'action'      => $p . 'misc/change_pkg.cgi?',
660     'label'       => emt('Reschedule'),
661     'actionlabel' => emt('Edit scheduled change for'),
662     'cust_pkg'    => $cust_pkg,
663     'width'       => 960,
664     'height'      => 490,
665   )
666 }
667
668 sub svc_recharge_link {
669   include( '/elements/popup_link-cust_svc.html',
670              'action'      => $p. 'misc/recharge_svc.html',
671              'label'       => emt('Recharge'),
672              'actionlabel' => emt('Recharge'),
673              'color'       => '#333399',
674              'cust_svc'    => shift,
675          )
676 }
677
678 sub pkg_autosuspend_time {
679   my $cust_pkg = shift or return '';
680   my $days = 7;
681   my $time = time;
682   my $pending_suspend = 0;
683   #this seems to be extremely inefficient...  and is slowing down all customer
684   #views
685   while ( $days > 0 &&
686           scalar(
687             grep { $_->part_event->action eq 'suspend' }
688             @{$cust_pkg->cust_main->due_cust_event( time => $time + 86400*$days,
689                                                     testonly => 1,
690                                                   ) }
691           )
692         )
693   {
694     $pending_suspend = 1;
695     $days--;
696   }
697
698   $pending_suspend ? time + ($days + 1) * 86400 : '';
699
700 }
701
702 </%init>