1 <style type="text/css">
20 /* #customer_menu .ui-menu-item */
21 #customer_menu > li.ui-state-focus {
22 background-color: #f8f8f8;
23 border-top: 1px solid transparent;
24 border-left: 1px solid transparent;
25 border-right: 1px solid transparent;
30 #customer_menu > li.ui-state-active {
31 border-top: 1px solid transparent;
32 border-left: 1px solid transparent;
33 border-right: 1px solid transparent;
36 #customer_menu > li > a {
37 border-top: 1px solid transparent;
38 border-left: 1px solid transparent;
39 border-right: 1px solid transparent;
45 #customer_menu a.current_show {
48 border-top: 1px solid #7e0079;
49 border-left: 1px solid #7e0079;
50 border-right: 1px solid #7e0079;
51 border-bottom: 1px solid #ffffff;
62 border-top-left-radius: .5em;
63 border-top-right-radius: .5em;
69 text-decoration: none;
74 border: 1px solid #7e0079;
76 box-shadow: #333333 1px 1px 2px;
79 #customer_menu ul li {
87 background: transparent;
90 #customer_menu li.ui-menu-divider {
91 border-color: #7e0079;
96 #customer_menu a:hover {
97 text-decoration: underline;
101 #customer_menu ul li.ui-state-focus {
102 background: transparent;
103 border: 1px solid transparent;
108 #customer_menu ul li.ui-state-active {
109 /* background: #f2c9ec; */
110 border: 1px solid transparent;
115 #customer_menu a .arrow {
122 <ul id="customer_menu">
123 % foreach my $submenu (@processed_menu) {
125 <% shift @$submenu %>
127 <ul class="customer_submenu">
128 % foreach my $link ( @$submenu ) {
137 <script type="text/javascript">
139 $("#customer_menu").menu({
140 position: { my: "left top", at: "left+1 bottom" },
142 $(this).menu("option", "position", { my:"left top", at:"left+1 bottom" } );
144 focus: function(e,ui) {
145 if ($("#customer_menu").get(0) !== $(ui).get(0).item.parent().get(0)) {
146 $(this).menu("option", "position", { my:"left top", at:"right+1 top"} );
156 my $cust_main = $opt{'cust_main'};
157 my $custnum = $cust_main->custnum;
158 my $curuser = $FS::CurrentUser::CurrentUser;
159 my $conf = FS::Conf->new;
161 my %payby = map { $_ => 1 } $conf->config('payby');
163 # cached for conditions, to avoid looking it up twice
164 my $invoicing_list_emailonly = $cust_main->invoicing_list_emailonly;
166 # nice declarative menu; should be a parameter to some kind of menu generator
173 label => 'Edit customer',
174 url => "edit/cust_main.cgi?$custnum",
175 acl => 'Edit customer'
178 label => 'Edit contacts',
179 url => "edit/cust_main-contacts.html?$custnum",
188 acl => 'Bill customer now',
189 content => sub { include( '/elements/bill.html',
190 label => emt('Bill now'),
191 url => $cgi->self_url,
192 custnum => shift->custnum,
198 popup => "misc/suspend_cust.html?custnum=$custnum",
199 acl => 'Suspend customer',
200 condition => sub { shift->unsuspended_pkgs > 0 },
201 actionlabel => 'Confirm Suspension',
205 label => 'Unsuspend',
206 popup => "misc/unsuspend_cust.html?custnum=$custnum",
207 acl => 'Unsuspend customer',
208 condition => sub { shift->suspended_pkgs > 0 },
209 actionlabel => 'Confirm Unsuspension',
213 popup => "misc/suspend_cust.html?custnum=$custnum",
214 acl => 'Cancel customer',
215 condition => sub { shift->ncancelled_pkgs > 0 },
216 actionlabel => 'Confirm Cancellation',
221 popup => "misc/merge_cust.html?custnum=$custnum",
222 acl => 'Merge customer',
223 actionlabel => 'Merge customer',
228 label => 'Refer a new customer',
229 url => "edit/cust_main.cgi?referral_custnum=$custnum",
230 confexists => '!disable_customer_referrals',
238 label => 'View this customer\'s referrals',
239 url => "search/cust_main.cgi?referral_custnum=$custnum",
240 confexists => '!disable_customer_referrals',
242 FS::cust_main->count('referral_custnum = ?', shift->custnum) > 0
246 label => 'View billing events',
247 url => "search/cust_event.html?custnum=$custnum",
248 acl => [ 'Billing event reports',
249 'View customer billing events' ],
252 label => 'Email a notice to this customer',
254 my $cust_main = shift;
255 my $agentnum = $cust_main->agentnum;
256 'misc/email-customers.html?table=cust_main;'.
257 'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=".
258 uri_escape($cgi->self_url);
260 condition => sub { $invoicing_list_emailonly },
261 acl => 'Bulk send customer notices',
271 popup => "edit/cust_main_note.cgi?custnum=$custnum",
272 actionlabel => 'Add note',
273 confexists => '!cust_main-disable_notes',
274 acl => 'Add customer note',
279 label => 'Attach file',
280 popup => "edit/cust_main_attach.cgi?custnum=$custnum",
281 actionlabel => 'Upload file',
282 confexists => '!disable_cust_attachment',
283 acl => 'Add attachment',
292 confexists => 'ticket_system'
297 label => 'Appointments',
298 show => 'appointments',
299 confexists => 'ticket_system',
300 acl => 'View appointments',
303 label => 'Schedule new appointment',
304 confexists => 'ticket_system',
305 acl => 'Make appointment',
306 popup => "elements/make_appointment.html?custnum=$custnum",
307 actionlabel => 'Schedule appointment',
312 label => 'Quotations',
313 show => 'quotations',
316 label => 'Create new quotation',
317 url => "edit/quotation.html?custnum=$custnum",
318 acl => 'Generate quotation',
327 label => 'New qualification',
328 popup => "misc/qual.html?custnum=$custnum",
329 actionlabel => 'New qualification',
333 acl => 'Qualify service',
336 label => 'Order new package',
337 popup => "misc/order_pkg.html?custnum=$custnum",
338 actionlabel => 'Order new package',
342 acl => 'Order customer package',
345 # it's just a popup, but there's some freaky CCH tax stuff in it
346 label => 'One-time charge',
348 include( '/elements/one_time_charge_link.html',
349 custnum => shift->custnum,
352 acl => 'One-time charge',
355 label => 'Move services between packages',
356 popup => "edit/bulk-cust_svc-pkgnum.html?custnum=$custnum",
357 actionlabel => 'Move services',
360 acl => 'Bulk move customer services',
363 label => 'Bulk order and cancel packages',
364 url => "edit/cust_pkg.cgi?$custnum",
365 acl => 'Bulk change customer packages',
373 label => 'Package reports',
374 url => "search/report_cust_pkg?custnum=$custnum",
377 label => 'View qualifications',
378 url => "search/qual.cgi?custnum=$custnum",
379 acl => 'Qualify service',
382 label => 'View accounts',
383 url => "search/report_svc_acct.html?custnum=$custnum",
386 label => 'View CDRs',
387 url => "search/report_cdr.html?custnum=$custnum",
392 label => 'Payment History',
393 show => 'payment_history',
396 # manual payment entry via edit/cust_pay
397 { label => 'Enter payment',
400 label => 'Enter check payment',
401 popup => "edit/cust_pay.cgi?popup=1;payby=BILL;custnum=$custnum",
402 actionlabel => 'Enter check payment',
405 acl => [ 'Post payment', 'Post check payment' ],
406 condition => sub { $payby{BILL} },
409 label => 'Enter cash payment',
410 popup => "edit/cust_pay.cgi?popup=1;payby=CASH;custnum=$custnum",
411 actionlabel => 'Enter cash payment',
414 acl => [ 'Post payment', 'Post cash payment' ],
415 condition => sub { $payby{CASH} },
418 label => 'Enter Western Union payment',
419 popup => "edit/cust_pay.cgi?popup=1;payby=WEST;custnum=$custnum",
420 actionlabel => 'Enter Western Union payment',
423 acl => [ 'Post payment', ],
424 condition => sub { $payby{WEST} },
427 label => 'Record manual (offline/POS) credit card payment',
428 popup => "edit/cust_pay.cgi?popup=1;payby=MCRD;custnum=$custnum",
429 actionlabel => 'Enter credit card payment',
432 acl => [ 'Post payment', ],
433 condition => sub { $payby{MCRD} },
436 label => 'Record manual (offline/POS) electronic check',
437 popup => "edit/cust_pay.cgi?popup=1;payby=MCHK;custnum=$custnum",
438 actionlabel => 'Enter credit card payment',
441 acl => [ 'Post payment', ],
442 condition => sub { $payby{MCHK} },
447 # realtime payments via payment.cgi
448 { label => 'Process payment',
451 label => 'Process credit card payment',
452 url => "misc/payment.cgi?payby=CARD;custnum=$custnum",
453 acl => [ 'Process payment', 'Process credit card payment', ],
454 condition => sub { $payby{CARD} or $payby{DCRD} },
457 label => 'Process electronic check payment',
458 url => "misc/payment.cgi?payby=CHEK;custnum=$custnum",
459 acl => [ 'Process payment', 'Process Echeck payment', ],
460 condition => sub { $payby{CHEK} or $payby{DCHK} },
470 label => 'Enter credit',
471 popup => "edit/cust_credit.cgi?custnum=$custnum",
472 actionlabel => 'Enter credit',
474 acl => 'Post credit',
477 label => 'Credit line items',
478 popup => "edit/credit-cust_bill_pkg.html?custnum=$custnum",
479 actionlabel => 'Credit line items',
482 acl => 'Credit line items',
484 FS::cust_bill->count('custnum = ?', shift->custnum) > 0
492 { label => 'Enter refund',
496 label => 'Enter check refund',
497 popup => "edit/cust_refund.cgi?popup=1;payby=BILL;custnum=$custnum",
498 actionlabel => 'Enter check refund',
500 acl => ['Post refund', 'Post check refund'],
501 condition => sub { $payby{BILL} },
504 label => 'Enter cash refund',
505 popup => "edit/cust_refund.cgi?popup=1;payby=CASH;custnum=$custnum",
506 actionlabel => 'Enter cash refund',
508 acl => ['Post refund', 'Post cash refund'],
509 condition => sub { $payby{CASH} },
512 label => 'Record manual (offline/POS) credit card refund',
513 popup => "edit/cust_refund.cgi?popup=1;payby=MCRD;custnum=$custnum",
514 actionlabel => 'Enter credit card refund',
516 acl => ['Post refund' ],
517 condition => sub { $payby{MCRD} },
520 label => 'Record manual (offline/POS) electronic check refund',
521 popup => "edit/cust_refund.cgi?popup=1;payby=MCHK;custnum=$custnum",
522 actionlabel => 'Enter electronic check refund',
524 acl => ['Post refund' ],
525 condition => sub { $payby{MCHK} },
537 label => 'Add tax adjustment',
538 popup => "edit/cust_tax_adjustment.html?custnum=$custnum",
539 actionlabel => 'Add tax adjustment',
541 confexists => 'enable_tax_adjustments',
542 acl => 'Add customer tax adjustment',
547 confexists => 'enable_tax_adjustments',
548 acl => 'Add customer tax adjustment',
552 label => 'Email statement to this customer',
554 my $cust_main = shift;
555 my $agentnum = $cust_main->agentnum;
556 'misc/email-customer-statement.html?table=cust_main;'.
557 'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=".
558 uri_escape($cgi->self_url);
560 condition => sub { $invoicing_list_emailonly },
561 acl => 'Resend invoices',
564 label => 'Download PDF statement',
565 url => "view/cust_main_statement-pdf.cgi?$custnum",
566 acl => 'View legacy typeset statements',
568 FS::cust_bill->count('custnum = ?', shift->custnum) > 0
572 label => 'Search invoices',
573 url => "search/report_cust_bill.html?custnum=$custnum",
574 acl => 'List invoices',
577 label => 'View tax exemptions',
578 url => "search/cust_tax_exempt_pkg.cgi?custnum=$custnum",
579 acl => 'View customer tax exemptions',
582 label => 'View tax adjustments',
583 url => "search/cust_tax_adjustment.html?custnum=$custnum",
584 confexists => 'enable_tax_adjustments',
585 acl => 'Add customer tax adjustment',
588 label => 'View pending payments',
589 url => "search/cust_pay_pending.html?magic=_date;statusNOT=done;custnum=$custnum",
590 acl => 'View pending payments',
592 FS::cust_pay_pending->count('custnum = ?', shift->custnum) > 0
599 label => 'Change History',
600 show => 'change_history',
601 acl => 'View customer history',
608 foreach my $submenu (@menu) {
612 foreach my $entry ( @$submenu ) {
613 # if the menu head was skipped, skip the whole menu
614 last if (!$first and !@links);
617 my $a = entry2link($entry, $cust_main, $opt{show});
618 push @links, $a if length($a);
623 push @processed_menu, \@links;
629 my( $entry, $cust_main, $show ) = @_;
632 if ( $entry->{acl} ) {
634 unless $FS::CurrentUser::CurrentUser->access_right( $entry->{acl} );
636 if ( $entry->{confexists} ) {
637 if ( $entry->{confexists} =~ /^!(.*)/ ) {
638 # confexists => !foo, a negative condition
639 return '' if FS::Conf->new->exists( $1 );
641 return '' unless FS::Conf->new->exists( $entry->{confexists} );
644 if ( $entry->{condition} ) {
645 return '' unless &{ $entry->{condition} }($cust_main);
648 my $label = emt($entry->{label});
650 if ( $entry->{submenu} ) {
652 my $a = '<a href="javascript:void(0);">'. $label.
653 '<img class="arrow" src="'. $p. 'images/arrow.right.black.png">'.
654 '</a><ul class="customer_subsubmenu">';
655 foreach my $submenu (@{ $entry->{submenu} }) {
656 $a .= '<li>'. entry2link($submenu, $cust_main, $show), '</li>';
663 my $target = $entry->{content}
667 if ( ref($target) eq 'CODE' ) {
668 $target = &$target($cust_main);
671 return $target if $entry->{content}; #the coderef specified the whole thing
673 if ( $entry->{show} ) {
675 # the menu head: always a link back to this page
676 $cgi->param('show', $entry->{show});
677 $target = $cgi->self_url;
678 $cgi->param('show', $show);
680 my $a = qq[ <A HREF="$target"];
681 $a .= ' class="current_show"' if $show eq $entry->{show};
682 return $a. qq[>$label</A> ];
684 } elsif ( $entry->{popup} ) {
686 $target =~ s/\$custnum/$custnum/g;
687 $target = $p.$target;
689 return include('/elements/popup_link.html',
697 } elsif ( $entry->{url} ) {
699 $target =~ s/\$custnum/$custnum/g;
700 $target = $p.$target;
702 return qq[ <A HREF="$target">$label</A> ];
705 die "bad entry $entry in menu: no url, popup or content";