Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / httemplate / view / cust_main / menu.html
1 <style type="text/css">
2
3 #customer_menu {
4   font-size: smaller;
5   border: none;
6   margin-top: .6em;
7   margin-bottom: 16px;
8 }
9
10 #customer_menu li {
11   float: left;
12   padding: .25em;
13 }
14
15 /* #customer_menu .ui-menu-item  */
16 #customer_menu > li {
17   background-color: #f8f8f8;
18   padding-left: 0px;
19 }
20
21 /* #customer_menu .ui-menu-item  */
22 #customer_menu > li.ui-state-focus {
23   background-color: #f8f8f8;
24   border: 1px solid transparent;
25 }
26
27 #customer_menu > li.ui-state-active {
28   background-color: #f8f8f8;
29   border: 1px solid transparent;
30 }
31
32 #customer_menu > li > a {
33   border-top: 1px solid transparent;
34   border-left: 1px solid transparent;
35   border-right: 1px solid transparent;
36   border-bottom: none;
37   padding: .5em .75em;
38 }
39
40 #customer_menu > li.ui-state-active > a {
41
42 /* if i could find something light enough that didn't look pink?
43      or is this too visually distracting and not the useful hint i think it is?
44   background: #ED55E7;
45 */
46 }
47
48 #customer_menu a.current_show {
49   font-weight: bold;
50   background: #FFFFFF;
51   border-top: 1px solid #7e0079;
52   border-left: 1px solid #7e0079;
53   border-right: 1px solid #7e0079;
54   border-bottom: 2px solid #ffffff;
55   margin-bottom: -2px;
56   border-bottom-left-radius: 2px;
57   border-bottom-right-radius: 2px;
58 }
59
60 #customer_menu a {
61   margin-left: 0;
62   margin-right: 1em;
63   margin-top: 0;
64   border-top-left-radius: .5em;
65   border-top-right-radius: .5em;
66
67   font-weight: normal;
68   background: #e0e0e0;
69   color: #525151;
70   white-space: nowrap;
71   text-decoration: none;
72 }
73
74 #customer_menu ul {
75   background: #ffffff;
76   border: 1px solid #7e0079;
77   border-radius: 2px;
78   box-shadow: #333333 1px 1px 2px;
79 }
80
81 #customer_menu ul li {
82   float: none;
83   margin-right: 2px;
84   margin-left: 2px;
85 }
86
87 #customer_menu ul a {
88   color: #333333;
89   background: transparent;
90 }
91
92 #customer_menu li.ui-menu-divider {
93   border-color: #7e0079;
94 /*  margin-right: 2px;
95   margin-left: 2px; */
96 }
97
98 #customer_menu a:hover {
99   text-decoration: underline;
100   color: #7e0079;
101 }
102
103 #customer_menu ul li.ui-state-focus {
104   background: transparent;
105   border: 1px solid transparent;
106   margin-right: 1px;
107   margin-left: 1px;
108 }
109
110 #customer_menu ul li.ui-state-active {
111   background: #f8f0fc;
112   border: 1px solid #7e0079;
113   border-radius: 2px;
114   margin-right: 1px;
115   margin-left: 1px;
116 }
117
118 #customer_menu a .arrow {
119   float: right;
120   background-image: url("<% $p %>images/arrow.right.black.png");
121   width: 3px;
122   height: 6px;
123   margin-top:4px;
124 }
125
126 @-moz-document url-prefix() {
127   #customer_menu a .arrow {
128     margin-top:-.8em;
129   }
130 }
131
132 </style>
133
134 <ul id="customer_menu">
135 % foreach my $submenu (@processed_menu) {
136   <li>
137     <% shift @$submenu %>
138 %   if ( @$submenu ) {
139       <ul class="customer_submenu">
140 %     foreach my $link ( @$submenu ) {
141         <li><% $link %></li>
142 %     }
143       </ul>
144 %   }
145   </li>
146 % }
147 </ul>
148
149 <script type="text/javascript">
150
151   $("#customer_menu").menu({
152     position: { my: "left top", at: "left+1 bottom+3" },
153     blur: function() {
154       $(this).menu("option", "position", { my:"left top", at:"left+1 bottom+3" } );
155     },
156     focus: function(e,ui) {
157       if ($("#customer_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
158         $(this).menu("option", "position", { my:"left top", at:"right+2 top"} );
159       }
160     },
161   });
162
163 </script>
164
165
166 <%init>
167 my %opt = @_;
168 my $cust_main = $opt{'cust_main'};
169 my $custnum = $cust_main->custnum;
170 my $curuser = $FS::CurrentUser::CurrentUser;
171 my $conf = FS::Conf->new;
172
173 my %payby = map { $_ => 1 } $conf->config('payby');
174
175 # cached for conditions, to avoid looking it up twice
176 my $invoicing_list_emailonly = $cust_main->invoicing_list_emailonly;
177
178 # nice declarative menu; should be a parameter to some kind of menu generator
179 my @menu = ( 
180   [
181     { show        => 'basics',
182       label       => 'Basics',
183     },
184     {
185       label       => 'Edit customer',
186       url         => "edit/cust_main.cgi?$custnum",
187       acl         => 'Edit customer'
188     },
189     {
190       label       => 'Edit contacts',
191       url         => "edit/cust_main-contacts.html?$custnum",
192     },
193
194     { label   => '-',
195       content => '-',
196     },
197
198     {
199       label       => 'Bill now',
200       acl         => 'Bill customer now',
201       content     => sub { include( '/elements/bill.html',
202                               label   => emt('Bill now'),
203                               url     => $cgi->self_url,
204                               custnum => shift->custnum,
205                            ),
206                      },
207     },
208     {
209       label       => 'Suspend',
210       popup       => "misc/suspend_cust.html?custnum=$custnum",
211       acl         => 'Suspend customer',
212       condition   => sub { shift->unsuspended_pkgs > 0 },
213       actionlabel => 'Confirm Suspension',
214       color       => '#ff9900',
215     },
216     {
217       label       => 'Unsuspend',
218       popup       => "misc/unsuspend_cust.html?custnum=$custnum",
219       acl         => 'Unsuspend customer',
220       condition   => sub { shift->suspended_pkgs > 0 },
221       actionlabel => 'Confirm Unsuspension',
222     },
223     {
224       label       => 'Cancel',
225       popup       => "misc/cancel_cust.html?custnum=$custnum",
226       acl         => 'Cancel customer',
227       condition   => sub { shift->ncancelled_pkgs > 0 },
228       actionlabel => 'Confirm Cancellation',
229       color       => '#ff0000',
230     },
231     {
232       label       => 'Merge',
233       popup       => "misc/merge_cust.html?custnum=$custnum",
234       acl         => 'Merge customer',
235       actionlabel => 'Merge customer',
236       width       => 569,
237       height      => 210,
238     },
239     {
240       label       => 'Refer a new customer',
241       url         => "edit/cust_main.cgi?referral_custnum=$custnum",
242       confexists  => '!disable_customer_referrals',
243     },
244
245     { label   => '-',
246       content => '-',
247     },
248
249     {
250       label       => 'View this customer\'s referrals',
251       url         => "search/cust_main.cgi?referral_custnum=$custnum",
252       confexists  => '!disable_customer_referrals',
253       condition   => sub {
254         FS::cust_main->count('referral_custnum = ?', shift->custnum) > 0
255       },
256     },
257     {
258       label       => 'View billing events',
259       url         => "search/cust_event.html?custnum=$custnum",
260       acl         => [ 'Billing event reports',
261                        'View customer billing events' ],
262     },
263     {
264       label       => 'Email a notice to this customer',
265       url         => sub {
266                       my $cust_main = shift;
267                       my $agentnum = $cust_main->agentnum;
268                       'misc/email-customers.html?table=cust_main;'.
269                       'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=".
270                       uri_escape($cgi->self_url);
271                      },
272       condition   => sub { $invoicing_list_emailonly },
273       acl         => 'Bulk send customer notices',
274     },
275   ],
276   [
277     {
278       label => 'Notes',
279       show  => 'notes',
280     },
281     {
282       label       => 'Add note',
283       popup       => "edit/cust_main_note.cgi?custnum=$custnum",
284       actionlabel => 'Add note',
285       confexists  => '!cust_main-disable_notes',
286       acl         => 'Add customer note',
287       width       => 875,
288       height      => 538,
289     },
290     {
291       label       => 'Attach file',
292       popup       => "edit/cust_main_attach.cgi?custnum=$custnum",
293       actionlabel => 'Upload file',
294       confexists  => '!disable_cust_attachment',
295       acl         => 'Add attachment',
296       width       => 480,
297       height      => 296,
298     },
299   ],
300   [
301     {
302       label => 'Tickets',
303       show  => 'tickets',
304       confexists => 'ticket_system'
305     },
306   ],
307   [
308     {
309       label => 'Appointments',
310       show  => 'appointments',
311       confexists => 'ticket_system',
312       acl   => 'View appointments',
313     },
314     {
315       label       => 'Schedule new appointment',
316       confexists  => 'ticket_system',
317       acl        => 'Make appointment',
318       popup       => "misc/make_appointment.html?custnum=$custnum",
319       actionlabel => 'Schedule appointment',
320     },
321   ],
322   [
323     {
324       label => 'Quotations',
325       show  => 'quotations',
326     },
327     {
328       label => 'Create new quotation',
329       url   => "edit/quotation.html?custnum=$custnum",
330       acl   => 'Generate quotation',
331     },
332   ],
333   [
334     {
335       label => 'Packages',
336       show  => 'packages',
337     },
338     {
339       label       => 'New qualification',
340       popup       => "misc/qual.html?custnum=$custnum",
341       actionlabel => 'New qualification',
342       color       => '#333399',
343       width       => 763,
344       height      => 436,
345       acl         => 'Qualify service',
346     },
347     {
348       label       => 'Order new package',
349       popup       => "misc/order_pkg.html?custnum=$custnum",
350       actionlabel => 'Order new package',
351       color       => '#333399',
352       width       => 960,
353       height      => 740,
354       acl         => 'Order customer package',
355     },
356     {
357       # it's just a popup, but there's some freaky CCH tax stuff in it
358       label       => 'One-time charge',
359       url         => "edit/quick-charge.html?custnum=$custnum",
360       acl         => 'One-time charge',
361     },
362     {
363       label       => 'Move services between packages',
364       popup       => "edit/bulk-cust_svc-pkgnum.html?custnum=$custnum",
365       actionlabel => 'Move services',
366       width       => 968,
367       height      => 575,
368       acl         => 'Bulk move customer services',
369     },
370     {
371       label       => 'Bulk order and cancel packages',
372       url         => "edit/cust_pkg.cgi?$custnum",
373       acl         => 'Bulk change customer packages',
374     },
375
376     { label   => '-',
377       content => '-',
378     },
379
380     {
381       label => 'Package reports',
382       url   => "search/report_cust_pkg.html?custnum=$custnum",
383     },
384     {
385       label => 'View qualifications',
386       url   => "search/qual.cgi?custnum=$custnum",
387       acl   => 'Qualify service',
388     },
389     {
390       label => 'View accounts',
391       url   => "search/report_svc_acct.html?custnum=$custnum",
392     },
393     {
394       label => 'View data usage',
395       popup => "search/report_sqlradius_usage-custnum.html?$custnum",
396       acl   => 'Usage: RADIUS sessions',
397       actionlabel => 'Data usage report',
398       width   => 480,
399       height  => 245,
400     },
401     {
402       label => 'View CDRs',
403       url   => "search/report_cdr.html?custnum=$custnum",
404       # XXX should have a condition that the customer has any CDR packages
405     },
406   ],
407   [
408     {
409       label => 'Payment History',
410       show  => 'payment_history',
411     },
412
413     # manual payment entry via edit/cust_pay
414     { label   => 'Enter payment',
415       submenu => [
416         {
417           label       => 'Enter check payment',
418           popup       => "edit/cust_pay.cgi?popup=1;payby=BILL;custnum=$custnum",
419           actionlabel => 'Enter check payment',
420           width       => 763,
421           height      => 392,
422           acl         => [ 'Post payment', 'Post check payment' ],
423         },
424         {
425           label       => 'Enter cash payment',
426           popup       => "edit/cust_pay.cgi?popup=1;payby=CASH;custnum=$custnum",
427           actionlabel => 'Enter cash payment',
428           width       => 763,
429           height      => 392,
430           acl         => [ 'Post payment', 'Post cash payment' ],
431         },
432         #{
433         #  label       => 'Enter Western Union payment',
434         #  popup       => "edit/cust_pay.cgi?popup=1;payby=WEST;custnum=$custnum",
435         #  actionlabel => 'Enter Western Union payment',
436         #  width       => 763,
437         #  height      => 392,
438         #  acl         => [ 'Post payment', ],
439         ##  condition   => sub { $payby{WEST} },
440         #},
441         #{
442         #  label       => 'Record manual (offline/POS) credit card payment',
443         #  popup       => "edit/cust_pay.cgi?popup=1;payby=MCRD;custnum=$custnum",
444         #  actionlabel => 'Enter credit card payment',
445         #  width       => 763,
446         #  height      => 392,
447         #  acl         => [ 'Post payment', ],
448         ##  condition   => sub { $payby{MCRD} },
449         #},
450         #{
451         #  label       => 'Record manual (offline/POS) electronic check',
452         #  popup       => "edit/cust_pay.cgi?popup=1;payby=MCHK;custnum=$custnum",
453         #  actionlabel => 'Enter credit card payment',
454         #  width       => 763,
455         #  height      => 392,
456         #  acl         => [ 'Post payment', ],
457         ##  condition   => sub { $payby{MCHK} },
458         #},
459       ],
460     },
461
462     # realtime payments via payment.cgi
463     { label   => 'Process payment',
464       submenu => [
465         {
466           label       => 'Process credit card payment',
467           url         => "misc/payment.cgi?payby=CARD;custnum=$custnum",
468           acl         => [ 'Process payment', 'Process credit card payment', ],
469           condition   => sub { $payby{CARD} or $payby{DCRD} },
470         },
471         {
472           label       => 'Process electronic check payment',
473           url         => "misc/payment.cgi?payby=CHEK;custnum=$custnum",
474           acl         => [ 'Process payment', 'Process Echeck payment', ],
475           condition   => sub { $payby{CHEK} or $payby{DCHK} },
476         },
477       ],
478     },
479
480     { label   => '-',
481       content => '-',
482     },
483
484     {
485       label       => 'Enter credit',
486       popup       => "edit/cust_credit.cgi?custnum=$custnum",
487       actionlabel => 'Enter credit',
488       width       => 763,
489       acl         => 'Post credit',
490     },
491     {
492       label       => 'Credit line items',
493       popup       => "edit/credit-cust_bill_pkg.html?custnum=$custnum",
494       actionlabel => 'Credit line items',
495       width       => 968,
496       height      => 575,
497       acl         => 'Credit line items',
498       condition   => sub {
499         FS::cust_bill->count('custnum = ?', shift->custnum) > 0
500       },
501     },
502
503     { label   => '-',
504       content => '-',
505     },
506
507     { label   => 'Enter refund',
508       submenu => [
509
510         {
511           label       => 'Enter check refund',
512           popup       => "edit/cust_refund.cgi?popup=1;payby=BILL;custnum=$custnum",
513           actionlabel => 'Enter check refund',
514           width       => 440,
515           acl         => ['Post refund', 'Post check refund'],
516         },
517         {
518           label       => 'Enter cash refund',
519           popup       => "edit/cust_refund.cgi?popup=1;payby=CASH;custnum=$custnum",
520           actionlabel => 'Enter cash refund',
521           width       => 392,
522           acl         => ['Post refund', 'Post cash refund'],
523         },
524         #{
525         #  label       => 'Record manual (offline/POS) credit card refund',
526         #  popup       => "edit/cust_refund.cgi?popup=1;payby=MCRD;custnum=$custnum",
527         #  actionlabel => 'Enter credit card refund',
528         #  width       => 440,
529         #  acl         => ['Post refund' ],
530         ##  condition   => sub { $payby{MCRD} },
531         #},
532         #{
533         #  label       => 'Record manual (offline/POS) electronic check refund',
534         #  popup       => "edit/cust_refund.cgi?popup=1;payby=MCHK;custnum=$custnum",
535         #  actionlabel => 'Enter electronic check refund',
536         #  width       => 440,
537         #  acl         => ['Post refund' ],
538         ##  condition   => sub { $payby{MCHK} },
539         #},
540
541       ],
542
543     },
544
545     { label   => '-',
546       content => '-',
547     },
548
549     {
550       label       => 'Add tax adjustment',
551       popup       => "edit/cust_tax_adjustment.html?custnum=$custnum",
552       actionlabel => 'Add tax adjustment',
553       height      => 200,
554       confexists  => 'enable_tax_adjustments',
555       acl         => 'Add customer tax adjustment',
556     },
557
558     { label       => '-',
559       content     => '-',
560       confexists  => 'enable_tax_adjustments',
561       acl         => 'Add customer tax adjustment',
562     },
563
564     {
565       label       => 'Email statement to this customer',
566       url         => sub {
567                       my $cust_main = shift;
568                       my $agentnum = $cust_main->agentnum;
569                       'misc/email-customer-statement.html?table=cust_main;'.
570                       'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=".
571                       uri_escape($cgi->self_url);
572                      },
573       condition   => sub { $invoicing_list_emailonly },
574       acl         => 'Resend invoices',
575     },
576     {
577       label       => 'Download PDF statement',
578       url         => "view/cust_main_statement-pdf.cgi?$custnum",
579       acl         => 'View legacy typeset statements',
580       condition   => sub {
581         FS::cust_bill->count('custnum = ?', shift->custnum) > 0
582       },
583     },
584     {
585       label       => 'Search invoices',
586       url         => "search/report_cust_bill.html?custnum=$custnum",
587       acl         => 'List invoices',
588     },
589     {
590       label       => 'View tax exemptions',
591       url         => "search/cust_tax_exempt_pkg.cgi?custnum=$custnum",
592       acl         => 'View customer tax exemptions',
593     },
594     {
595       label       => 'View tax adjustments',
596       url         => "search/cust_tax_adjustment.html?custnum=$custnum",
597       confexists  => 'enable_tax_adjustments',
598       acl         => 'Add customer tax adjustment',
599     },
600     {
601       label       => 'View pending payments',
602       url         => "search/cust_pay_pending.html?magic=_date;statusNOT=done;custnum=$custnum",
603       acl         => 'View pending payments',
604       condition   => sub { 
605         FS::cust_pay_pending->count('custnum = ?', shift->custnum) > 0
606       },
607     },
608
609   ],
610   [
611     {
612       label => 'Change History',
613       show  => 'change_history',
614       acl   => 'View customer history',
615     },
616   ],
617 );
618
619
620 my @processed_menu;
621 foreach my $submenu (@menu) {
622
623   my @links;
624   my $first = 1;
625   foreach my $entry ( @$submenu ) {
626     # if the menu head was skipped, skip the whole menu
627     last if (!$first and !@links);
628     $first = 0;
629
630     my $a = entry2link($entry, $cust_main, $opt{show});
631     push @links, $a if length($a);
632
633   } # foreach $entry
634
635   if (@links) {
636     push @processed_menu, \@links;
637   }
638
639 }
640
641 sub entry2link {
642     my( $entry, $cust_main, $show ) = @_;
643
644     # check conditions
645     if ( $entry->{acl} ) {
646       return ''
647         unless $FS::CurrentUser::CurrentUser->access_right( $entry->{acl} );
648     }
649     if ( $entry->{confexists} ) {
650       if ( $entry->{confexists} =~ /^!(.*)/ ) {
651         # confexists => !foo, a negative condition
652         return '' if FS::Conf->new->exists( $1 );
653       } else {
654         return '' unless FS::Conf->new->exists( $entry->{confexists} );
655       }
656     }
657     if ( $entry->{condition} ) {
658       return '' unless &{ $entry->{condition} }($cust_main);
659     }
660
661     my $label = emt($entry->{label});
662
663     if ( $entry->{submenu} ) {
664
665       my $a = '<a href="javascript:void(0);">'. $label.
666               '<span class="arrow"></span>'.
667               '</a><ul class="customer_subsubmenu">';
668       foreach my $submenu (@{ $entry->{submenu} }) {
669         $a .= '<li>'. entry2link($submenu, $cust_main, $show), '</li>';
670       }
671
672       return $a. '</ul>';
673
674     }
675
676     my $target = $entry->{content}
677               || $entry->{popup}
678               || $entry->{url};
679
680     if ( ref($target) eq 'CODE' ) {
681       $target = &$target($cust_main);
682     }
683
684     return $target if $entry->{content}; #the coderef specified the whole thing
685
686     if ( $entry->{show} ) {
687
688       # the menu head: always a link back to this page
689       $cgi->param('show', $entry->{show});
690       $target = $cgi->self_url;
691       $cgi->param('show', $show);
692
693       my $a = qq[ <A HREF="$target"];
694       $a .= ' class="current_show"' if $show eq $entry->{show};
695       return $a. qq[>$label</A> ];
696
697     } elsif ( $entry->{popup} ) {
698
699       $target =~ s/\$custnum/$custnum/g;
700       $target = $p.$target;
701
702       return include('/elements/popup_link.html',
703         action  => $target,
704         width   => 616,
705         height  => 410,
706         %$entry,
707         label   => $label,
708       );
709
710     } elsif ( $entry->{url} ) {
711
712       $target =~ s/\$custnum/$custnum/g;
713       $target = $p.$target;
714
715       return qq[ <A HREF="$target">$label</A> ];
716
717     } else {
718       die "bad entry ". join(',',%$entry). " in menu: no url, popup or content";
719     }
720
721 }
722
723 </%init>