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