<%init> my %opt = @_; my $cust_main = $opt{'cust_main'}; my $custnum = $cust_main->custnum; my $curuser = $FS::CurrentUser::CurrentUser; my $conf = FS::Conf->new; my %payby = map { $_ => 1 } $conf->config('payby'); # cached for conditions, to avoid looking it up twice my $invoicing_list_emailonly = $cust_main->invoicing_list_emailonly; # nice declarative menu; should be a parameter to some kind of menu generator my @menu = ( [ { show => 'basics', label => 'Basics', }, { label => 'Edit customer', url => "edit/cust_main.cgi?$custnum", acl => 'Edit customer' }, { label => 'Edit contacts', url => "edit/cust_main-contacts.html?$custnum", }, { label => '-', content => '-', }, { label => 'Bill now', acl => 'Bill customer now', content => sub { include( '/elements/bill.html', label => emt('Bill now'), url => $cgi->self_url, custnum => shift->custnum, ), }, }, { label => 'Suspend', popup => "misc/suspend_cust.html?custnum=$custnum", acl => 'Suspend customer', condition => sub { shift->unsuspended_pkgs > 0 }, actionlabel => 'Confirm Suspension', color => '#ff9900', }, { label => 'Unsuspend', popup => "misc/unsuspend_cust.html?custnum=$custnum", acl => 'Unsuspend customer', condition => sub { shift->suspended_pkgs > 0 }, actionlabel => 'Confirm Unsuspension', }, { label => 'Cancel', popup => "misc/cancel_cust.html?custnum=$custnum", acl => 'Cancel customer', condition => sub { shift->ncancelled_pkgs > 0 }, actionlabel => 'Confirm Cancellation', color => '#ff0000', }, { label => 'Merge', popup => "misc/merge_cust.html?custnum=$custnum", acl => 'Merge customer', actionlabel => 'Merge customer', width => 569, height => 210, }, { label => 'Refer a new customer', url => "edit/cust_main.cgi?referral_custnum=$custnum", confexists => '!disable_customer_referrals', }, { label => '-', content => '-', }, { label => 'View this customer\'s referrals', url => "search/cust_main.cgi?referral_custnum=$custnum", confexists => '!disable_customer_referrals', condition => sub { FS::cust_main->count('referral_custnum = ?', shift->custnum) > 0 }, }, { label => 'View billing events', url => "search/cust_event.html?custnum=$custnum", acl => [ 'Billing event reports', 'View customer billing events' ], }, { label => 'Email a notice to this customer', url => sub { my $cust_main = shift; my $agentnum = $cust_main->agentnum; 'misc/email-customers.html?table=cust_main;'. 'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=". uri_escape($cgi->self_url); }, condition => sub { $invoicing_list_emailonly }, acl => 'Bulk send customer notices', }, ], [ { label => 'Notes', show => 'notes', }, { label => 'Add note', popup => "edit/cust_main_note.cgi?custnum=$custnum", actionlabel => 'Add note', confexists => '!cust_main-disable_notes', acl => 'Add customer note', width => 875, height => 538, }, { label => 'Attach file', popup => "edit/cust_main_attach.cgi?custnum=$custnum", actionlabel => 'Upload file', confexists => '!disable_cust_attachment', acl => 'Add attachment', width => 480, height => 296, }, ], [ { label => 'Tickets', show => 'tickets', confexists => 'ticket_system' }, ], [ { label => 'Appointments', show => 'appointments', confexists => 'ticket_system', acl => 'View appointments', }, { label => 'Schedule new appointment', confexists => 'ticket_system', acl => 'Make appointment', popup => "misc/make_appointment.html?custnum=$custnum", actionlabel => 'Schedule appointment', }, ], [ { label => 'Quotations', show => 'quotations', }, { label => 'Create new quotation', url => "edit/quotation.html?custnum=$custnum", acl => 'Generate quotation', }, ], [ { label => 'Packages', show => 'packages', }, { label => 'New qualification', popup => "misc/qual.html?custnum=$custnum", actionlabel => 'New qualification', color => '#333399', width => 763, height => 436, acl => 'Qualify service', }, { label => 'Order new package', popup => "misc/order_pkg.html?custnum=$custnum", actionlabel => 'Order new package', color => '#333399', width => 960, height => 740, acl => 'Order customer package', }, { # it's just a popup, but there's some freaky CCH tax stuff in it label => 'One-time charge', url => "edit/quick-charge.html?custnum=$custnum", acl => 'One-time charge', }, { label => 'Move services between packages', popup => "edit/bulk-cust_svc-pkgnum.html?custnum=$custnum", actionlabel => 'Move services', width => 968, height => 575, acl => 'Bulk move customer services', }, { label => 'Bulk order and cancel packages', url => "edit/cust_pkg.cgi?$custnum", acl => 'Bulk change customer packages', }, { label => '-', content => '-', }, { label => 'Package reports', url => "search/report_cust_pkg.html?custnum=$custnum", }, { label => 'View qualifications', url => "search/qual.cgi?custnum=$custnum", acl => 'Qualify service', }, { label => 'View accounts', url => "search/report_svc_acct.html?custnum=$custnum", }, { label => 'View data usage', popup => "search/report_sqlradius_usage-custnum.html?$custnum", acl => 'Usage: RADIUS sessions', actionlabel => 'Data usage report', width => 480, height => 345, condition => sub { shift->num_usage_pkgs > 0 }, }, { label => 'View CDRs', url => "search/report_cdr.html?custnum=$custnum", # XXX should have a condition that the customer has any CDR packages }, ], [ { label => 'Payment History', show => 'payment_history', }, # manual payment entry via edit/cust_pay { label => 'Enter payment', submenu => [ { label => 'Enter check payment', popup => "edit/cust_pay.cgi?popup=1;payby=BILL;custnum=$custnum", actionlabel => 'Enter check payment', width => 763, height => 392, acl => [ 'Post payment', 'Post check payment' ], }, { label => 'Enter cash payment', popup => "edit/cust_pay.cgi?popup=1;payby=CASH;custnum=$custnum", actionlabel => 'Enter cash payment', width => 763, height => 392, acl => [ 'Post payment', 'Post cash payment' ], }, #{ # label => 'Enter Western Union payment', # popup => "edit/cust_pay.cgi?popup=1;payby=WEST;custnum=$custnum", # actionlabel => 'Enter Western Union payment', # width => 763, # height => 392, # acl => [ 'Post payment', ], ## condition => sub { $payby{WEST} }, #}, #{ # label => 'Record manual (offline/POS) credit card payment', # popup => "edit/cust_pay.cgi?popup=1;payby=MCRD;custnum=$custnum", # actionlabel => 'Enter credit card payment', # width => 763, # height => 392, # acl => [ 'Post payment', ], ## condition => sub { $payby{MCRD} }, #}, #{ # label => 'Record manual (offline/POS) electronic check', # popup => "edit/cust_pay.cgi?popup=1;payby=MCHK;custnum=$custnum", # actionlabel => 'Enter credit card payment', # width => 763, # height => 392, # acl => [ 'Post payment', ], ## condition => sub { $payby{MCHK} }, #}, ], }, # realtime payments via payment.cgi { label => 'Process payment', submenu => [ { label => 'Process credit card payment', url => "misc/payment.cgi?payby=CARD;custnum=$custnum", acl => [ 'Process payment', 'Process credit card payment', ], condition => sub { $payby{CARD} or $payby{DCRD} }, }, { label => 'Process electronic check payment', url => "misc/payment.cgi?payby=CHEK;custnum=$custnum", acl => [ 'Process payment', 'Process Echeck payment', ], condition => sub { $payby{CHEK} or $payby{DCHK} }, }, ], }, { label => '-', content => '-', }, { label => 'Enter credit', popup => "edit/cust_credit.cgi?custnum=$custnum", actionlabel => 'Enter credit', width => 763, acl => 'Post credit', }, { label => 'Credit line items', popup => "edit/credit-cust_bill_pkg.html?custnum=$custnum", actionlabel => 'Credit line items', width => 968, height => 575, acl => 'Credit line items', condition => sub { FS::cust_bill->count('custnum = ?', shift->custnum) > 0 }, }, { label => '-', content => '-', }, { label => 'Enter refund', submenu => [ { label => 'Enter check refund', popup => "edit/cust_refund.cgi?popup=1;payby=BILL;custnum=$custnum", actionlabel => 'Enter check refund', width => 440, acl => ['Post refund', 'Post check refund'], }, { label => 'Enter cash refund', popup => "edit/cust_refund.cgi?popup=1;payby=CASH;custnum=$custnum", actionlabel => 'Enter cash refund', width => 392, acl => ['Post refund', 'Post cash refund'], }, #{ # label => 'Record manual (offline/POS) credit card refund', # popup => "edit/cust_refund.cgi?popup=1;payby=MCRD;custnum=$custnum", # actionlabel => 'Enter credit card refund', # width => 440, # acl => ['Post refund' ], ## condition => sub { $payby{MCRD} }, #}, #{ # label => 'Record manual (offline/POS) electronic check refund', # popup => "edit/cust_refund.cgi?popup=1;payby=MCHK;custnum=$custnum", # actionlabel => 'Enter electronic check refund', # width => 440, # acl => ['Post refund' ], ## condition => sub { $payby{MCHK} }, #}, ], }, { label => '-', content => '-', }, { label => 'Add tax adjustment', popup => "edit/cust_tax_adjustment.html?custnum=$custnum", actionlabel => 'Add tax adjustment', height => 200, confexists => 'enable_tax_adjustments', acl => 'Add customer tax adjustment', }, { label => '-', content => '-', confexists => 'enable_tax_adjustments', acl => 'Add customer tax adjustment', }, { label => 'Email statement to this customer', url => sub { my $cust_main = shift; my $agentnum = $cust_main->agentnum; 'misc/email-customer-statement.html?table=cust_main;'. 'agent_virt_agentnum='.$agentnum.";custnum=$custnum;url=". uri_escape($cgi->self_url); }, condition => sub { $invoicing_list_emailonly }, acl => 'Resend invoices', }, { label => 'Download PDF statement', url => "view/cust_main_statement-pdf.cgi?$custnum", acl => 'View legacy typeset statements', condition => sub { FS::cust_bill->count('custnum = ?', shift->custnum) > 0 }, }, { label => 'Search invoices', url => "search/report_cust_bill.html?custnum=$custnum", acl => 'List invoices', }, { label => 'View tax exemptions', url => "search/cust_tax_exempt_pkg.cgi?custnum=$custnum", acl => 'View customer tax exemptions', }, { label => 'View tax adjustments', url => "search/cust_tax_adjustment.html?custnum=$custnum", confexists => 'enable_tax_adjustments', acl => 'Add customer tax adjustment', }, { label => 'View pending payments', url => "search/cust_pay_pending.html?magic=_date;statusNOT=done;custnum=$custnum", acl => 'View pending payments', condition => sub { FS::cust_pay_pending->count('custnum = ?', shift->custnum) > 0 }, }, ], [ { label => 'Change History', show => 'change_history', acl => 'View customer history', }, ], ); my @processed_menu; foreach my $submenu (@menu) { my @links; my $first = 1; foreach my $entry ( @$submenu ) { # if the menu head was skipped, skip the whole menu last if (!$first and !@links); $first = 0; my $a = entry2link($entry, $cust_main, $opt{show}); push @links, $a if length($a); } # foreach $entry if (@links) { push @processed_menu, \@links; } } sub entry2link { my( $entry, $cust_main, $show ) = @_; # check conditions if ( $entry->{acl} ) { return '' unless $FS::CurrentUser::CurrentUser->access_right( $entry->{acl} ); } if ( $entry->{confexists} ) { if ( $entry->{confexists} =~ /^!(.*)/ ) { # confexists => !foo, a negative condition return '' if FS::Conf->new->exists( $1 ); } else { return '' unless FS::Conf->new->exists( $entry->{confexists} ); } } if ( $entry->{condition} ) { return '' unless &{ $entry->{condition} }($cust_main); } my $label = emt($entry->{label}); if ( $entry->{submenu} ) { my $a = ''. $label. ''. ''; } my $target = $entry->{content} || $entry->{popup} || $entry->{url}; if ( ref($target) eq 'CODE' ) { $target = &$target($cust_main); } return $target if $entry->{content}; #the coderef specified the whole thing if ( $entry->{show} ) { # the menu head: always a link back to this page $cgi->param('show', $entry->{show}); $target = $cgi->self_url; $cgi->param('show', $show); my $a = qq[ {show}; return $a. qq[>$label ]; } elsif ( $entry->{popup} ) { $target =~ s/\$custnum/$custnum/g; $target = $p.$target; return include('/elements/popup_link.html', action => $target, width => 616, height => 410, %$entry, label => $label, ); } elsif ( $entry->{url} ) { $target =~ s/\$custnum/$custnum/g; $target = $p.$target; return qq[ $label ]; } else { die "bad entry ". join(',',%$entry). " in menu: no url, popup or content"; } }