9e194f42dff167fa5059b896b47db80666bf8359
[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 CDRs',
395       url   => "search/report_cdr.html?custnum=$custnum",
396     },
397   ],
398   [
399     {
400       label => 'Payment History',
401       show  => 'payment_history',
402     },
403
404     # manual payment entry via edit/cust_pay
405     { label   => 'Enter payment',
406       submenu => [
407         {
408           label       => 'Enter check payment',
409           popup       => "edit/cust_pay.cgi?popup=1;payby=BILL;custnum=$custnum",
410           actionlabel => 'Enter check payment',
411           width       => 763,
412           height      => 392,
413           acl         => [ 'Post payment', 'Post check payment' ],
414         },
415         {
416           label       => 'Enter cash payment',
417           popup       => "edit/cust_pay.cgi?popup=1;payby=CASH;custnum=$custnum",
418           actionlabel => 'Enter cash payment',
419           width       => 763,
420           height      => 392,
421           acl         => [ 'Post payment', 'Post cash payment' ],
422         },
423         #{
424         #  label       => 'Enter Western Union payment',
425         #  popup       => "edit/cust_pay.cgi?popup=1;payby=WEST;custnum=$custnum",
426         #  actionlabel => 'Enter Western Union payment',
427         #  width       => 763,
428         #  height      => 392,
429         #  acl         => [ 'Post payment', ],
430         ##  condition   => sub { $payby{WEST} },
431         #},
432         #{
433         #  label       => 'Record manual (offline/POS) credit card payment',
434         #  popup       => "edit/cust_pay.cgi?popup=1;payby=MCRD;custnum=$custnum",
435         #  actionlabel => 'Enter credit card payment',
436         #  width       => 763,
437         #  height      => 392,
438         #  acl         => [ 'Post payment', ],
439         ##  condition   => sub { $payby{MCRD} },
440         #},
441         #{
442         #  label       => 'Record manual (offline/POS) electronic check',
443         #  popup       => "edit/cust_pay.cgi?popup=1;payby=MCHK;custnum=$custnum",
444         #  actionlabel => 'Enter credit card payment',
445         #  width       => 763,
446         #  height      => 392,
447         #  acl         => [ 'Post payment', ],
448         ##  condition   => sub { $payby{MCHK} },
449         #},
450       ],
451     },
452
453     # realtime payments via payment.cgi
454     { label   => 'Process payment',
455       submenu => [
456         {
457           label       => 'Process credit card payment',
458           url         => "misc/payment.cgi?payby=CARD;custnum=$custnum",
459           acl         => [ 'Process payment', 'Process credit card payment', ],
460           condition   => sub { $payby{CARD} or $payby{DCRD} },
461         },
462         {
463           label       => 'Process electronic check payment',
464           url         => "misc/payment.cgi?payby=CHEK;custnum=$custnum",
465           acl         => [ 'Process payment', 'Process Echeck payment', ],
466           condition   => sub { $payby{CHEK} or $payby{DCHK} },
467         },
468       ],
469     },
470
471     { label   => '-',
472       content => '-',
473     },
474
475     {
476       label       => 'Enter credit',
477       popup       => "edit/cust_credit.cgi?custnum=$custnum",
478       actionlabel => 'Enter credit',
479       width       => 763,
480       acl         => 'Post credit',
481     },
482     {
483       label       => 'Credit line items',
484       popup       => "edit/credit-cust_bill_pkg.html?custnum=$custnum",
485       actionlabel => 'Credit line items',
486       width       => 968,
487       height      => 575,
488       acl         => 'Credit line items',
489       condition   => sub {
490         FS::cust_bill->count('custnum = ?', shift->custnum) > 0
491       },
492     },
493
494     { label   => '-',
495       content => '-',
496     },
497
498     { label   => 'Enter refund',
499       submenu => [
500
501         {
502           label       => 'Enter check refund',
503           popup       => "edit/cust_refund.cgi?popup=1;payby=BILL;custnum=$custnum",
504           actionlabel => 'Enter check refund',
505           width       => 440,
506           acl         => ['Post refund', 'Post check refund'],
507         },
508         {
509           label       => 'Enter cash refund',
510           popup       => "edit/cust_refund.cgi?popup=1;payby=CASH;custnum=$custnum",
511           actionlabel => 'Enter cash refund',
512           width       => 392,
513           acl         => ['Post refund', 'Post cash refund'],
514         },
515         #{
516         #  label       => 'Record manual (offline/POS) credit card refund',
517         #  popup       => "edit/cust_refund.cgi?popup=1;payby=MCRD;custnum=$custnum",
518         #  actionlabel => 'Enter credit card refund',
519         #  width       => 440,
520         #  acl         => ['Post refund' ],
521         ##  condition   => sub { $payby{MCRD} },
522         #},
523         #{
524         #  label       => 'Record manual (offline/POS) electronic check refund',
525         #  popup       => "edit/cust_refund.cgi?popup=1;payby=MCHK;custnum=$custnum",
526         #  actionlabel => 'Enter electronic check refund',
527         #  width       => 440,
528         #  acl         => ['Post refund' ],
529         ##  condition   => sub { $payby{MCHK} },
530         #},
531
532       ],
533
534     },
535
536     { label   => '-',
537       content => '-',
538     },
539
540     {
541       label       => 'Add tax adjustment',
542       popup       => "edit/cust_tax_adjustment.html?custnum=$custnum",
543       actionlabel => 'Add tax adjustment',
544       height      => 200,
545       confexists  => 'enable_tax_adjustments',
546       acl         => 'Add customer tax adjustment',
547     },
548
549     { label       => '-',
550       content     => '-',
551       confexists  => 'enable_tax_adjustments',
552       acl         => 'Add customer tax adjustment',
553     },
554
555     {
556       label       => 'Email statement to this customer',
557       url         => sub {
558                       my $cust_main = shift;
559                       my $agentnum = $cust_main->agentnum;
560                       'misc/email-customer-statement.html?table=cust_main;'.
561                       'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=".
562                       uri_escape($cgi->self_url);
563                      },
564       condition   => sub { $invoicing_list_emailonly },
565       acl         => 'Resend invoices',
566     },
567     {
568       label       => 'Download PDF statement',
569       url         => "view/cust_main_statement-pdf.cgi?$custnum",
570       acl         => 'View legacy typeset statements',
571       condition   => sub {
572         FS::cust_bill->count('custnum = ?', shift->custnum) > 0
573       },
574     },
575     {
576       label       => 'Search invoices',
577       url         => "search/report_cust_bill.html?custnum=$custnum",
578       acl         => 'List invoices',
579     },
580     {
581       label       => 'View tax exemptions',
582       url         => "search/cust_tax_exempt_pkg.cgi?custnum=$custnum",
583       acl         => 'View customer tax exemptions',
584     },
585     {
586       label       => 'View tax adjustments',
587       url         => "search/cust_tax_adjustment.html?custnum=$custnum",
588       confexists  => 'enable_tax_adjustments',
589       acl         => 'Add customer tax adjustment',
590     },
591     {
592       label       => 'View pending payments',
593       url         => "search/cust_pay_pending.html?magic=_date;statusNOT=done;custnum=$custnum",
594       acl         => 'View pending payments',
595       condition   => sub { 
596         FS::cust_pay_pending->count('custnum = ?', shift->custnum) > 0
597       },
598     },
599
600   ],
601   [
602     {
603       label => 'Change History',
604       show  => 'change_history',
605       acl   => 'View customer history',
606     },
607   ],
608 );
609
610
611 my @processed_menu;
612 foreach my $submenu (@menu) {
613
614   my @links;
615   my $first = 1;
616   foreach my $entry ( @$submenu ) {
617     # if the menu head was skipped, skip the whole menu
618     last if (!$first and !@links);
619     $first = 0;
620
621     my $a = entry2link($entry, $cust_main, $opt{show});
622     push @links, $a if length($a);
623
624   } # foreach $entry
625
626   if (@links) {
627     push @processed_menu, \@links;
628   }
629
630 }
631
632 sub entry2link {
633     my( $entry, $cust_main, $show ) = @_;
634
635     # check conditions
636     if ( $entry->{acl} ) {
637       return ''
638         unless $FS::CurrentUser::CurrentUser->access_right( $entry->{acl} );
639     }
640     if ( $entry->{confexists} ) {
641       if ( $entry->{confexists} =~ /^!(.*)/ ) {
642         # confexists => !foo, a negative condition
643         return '' if FS::Conf->new->exists( $1 );
644       } else {
645         return '' unless FS::Conf->new->exists( $entry->{confexists} );
646       }
647     }
648     if ( $entry->{condition} ) {
649       return '' unless &{ $entry->{condition} }($cust_main);
650     }
651
652     my $label = emt($entry->{label});
653
654     if ( $entry->{submenu} ) {
655
656       my $a = '<a href="javascript:void(0);">'. $label.
657               '<span class="arrow"></span>'.
658               '</a><ul class="customer_subsubmenu">';
659       foreach my $submenu (@{ $entry->{submenu} }) {
660         $a .= '<li>'. entry2link($submenu, $cust_main, $show), '</li>';
661       }
662
663       return $a. '</ul>';
664
665     }
666
667     my $target = $entry->{content}
668               || $entry->{popup}
669               || $entry->{url};
670
671     if ( ref($target) eq 'CODE' ) {
672       $target = &$target($cust_main);
673     }
674
675     return $target if $entry->{content}; #the coderef specified the whole thing
676
677     if ( $entry->{show} ) {
678
679       # the menu head: always a link back to this page
680       $cgi->param('show', $entry->{show});
681       $target = $cgi->self_url;
682       $cgi->param('show', $show);
683
684       my $a = qq[ <A HREF="$target"];
685       $a .= ' class="current_show"' if $show eq $entry->{show};
686       return $a. qq[>$label</A> ];
687
688     } elsif ( $entry->{popup} ) {
689
690       $target =~ s/\$custnum/$custnum/g;
691       $target = $p.$target;
692
693       return include('/elements/popup_link.html',
694         action  => $target,
695         width   => 616,
696         height  => 410,
697         %$entry,
698         label   => $label,
699       );
700
701     } elsif ( $entry->{url} ) {
702
703       $target =~ s/\$custnum/$custnum/g;
704       $target = $p.$target;
705
706       return qq[ <A HREF="$target">$label</A> ];
707
708     } else {
709       die "bad entry ". join(',',%$entry). " in menu: no url, popup or content";
710     }
711
712 }
713
714 </%init>