diff options
Diffstat (limited to 'httemplate')
20 files changed, 646 insertions, 28 deletions
diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 7b2e55a55..7a6191171 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -420,8 +420,9 @@ my @deleteable = qw( invoice_latexreturnaddress invoice_htmlreturnaddress ); my %deleteable = map { $_ => 1 } @deleteable; my @sections = (qw( - required billing invoicing notification UI API self-service ticketing - network_monitoring username password session shell BIND telephony + required billing invoicing notification email_to_voice_services UI + API self-service ticketing network_monitoring username password + session shell BIND telephony ), '', 'deprecated' ); diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi index 32da4543e..c79c39a80 100755 --- a/httemplate/edit/cust_refund.cgi +++ b/httemplate/edit/cust_refund.cgi @@ -102,6 +102,22 @@ <TD ALIGN="right">Check #</TD> <TD COLSPAN=2><INPUT TYPE="text" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10></TD> </TR> +% } +% elsif ($payby eq 'CHEK' || $payby eq 'CARD') { + +% if ( $conf->exists("batch-enable") +% || grep $payby eq $_, $conf->config('batch-enable_payby') +% ) { +% if ( grep $payby eq $_, $conf->config('realtime-disable_payby') ) { + <INPUT TYPE="hidden" NAME="batch" VALUE="1"> +% } else { + <TR> + <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="batch" VALUE="1" ID="batch" <% ($batchnum || $batch) ? 'checked' : '' %> ></TD> + <TD ALIGN="left"> <% mt('Add to current batch') |h %></TD> + </TR> +% } +% } + % } else { <INPUT TYPE="hidden" NAME="payinfo" VALUE=""> % } @@ -138,16 +154,18 @@ my $payby = $cgi->param('payby'); my $payinfo = $cgi->param('payinfo'); my $reason = $cgi->param('reason'); my $link = $cgi->param('popup') ? 'popup' : ''; +my $batch = $cgi->param('batch'); die "access denied" unless $FS::CurrentUser::CurrentUser->refund_access_right($payby); -my( $paynum, $cust_pay ) = ( '', '' ); +my( $paynum, $cust_pay, $batchnum ) = ( '', '', '' ); if ( $cgi->param('paynum') =~ /^(\d+)$/ ) { $paynum = $1; $cust_pay = qsearchs('cust_pay', { paynum=>$paynum } ) or die "unknown payment # $paynum"; $refund ||= $cust_pay->unrefunded; + $batchnum = $cust_pay->batchnum; if ( $custnum ) { die "payment # $paynum is not for specified customer # $custnum" unless $custnum == $cust_pay->custnum; diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi index 764f2deb7..44605bf42 100755 --- a/httemplate/edit/process/cust_refund.cgi +++ b/httemplate/edit/process/cust_refund.cgi @@ -42,18 +42,58 @@ if ( $error ) { } elsif ( $payby =~ /^(CARD|CHEK)$/ ) { my %options = (); my $bop = $FS::payby::payby2bop{$1}; + + my %payby2fields = ( + 'CARD' => [ qw( address1 address2 city county state zip country ) ], + 'CHEK' => [ qw( ss paytype paystate stateid stateid_state ) ], + ); + my %type = ( 'CARD' => 'credit card', + 'CHEK' => 'electronic check (ACH)', + ); + +## +# now run the refund +## + $cgi->param('refund') =~ /^(\d*)(\.\d{2})?$/ or die "illegal refund amount ". $cgi->param('refund'); my $refund = "$1$2"; $cgi->param('paynum') =~ /^(\d*)$/ or die "Illegal paynum!"; my $paynum = $1; my $paydate = $cgi->param('exp_year'). '-'. $cgi->param('exp_month'). '-01'; - $options{'paydate'} = $paydate if $paydate =~ /^\d{2,4}-\d{1,2}-01$/; - $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund, + + if ( $cgi->param('batch') ) { + $paydate = "2037-12-01" unless $paydate; + $error ||= $cust_main->batch_card( + 'payby' => $payby, + 'amount' => $refund, + #'payinfo' => $payinfo, + #'paydate' => $paydate, + #'payname' => $payname, + 'paycode' => 'C', + map { $_ => scalar($cgi->param($_)) } + @{$payby2fields{$payby}} + ); + errorpage($error) if $error; + + my %hash = map { + $_, scalar($cgi->param($_)) + } fields('cust_refund'); + + my $new = new FS::cust_refund ( { 'paynum' => $paynum, + %hash, + } ); + $error = $new->insert; + + # if not a batch refund run realtime. + } else { + $options{'paydate'} = $paydate if $paydate =~ /^\d{2,4}-\d{1,2}-01$/; + $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund, 'paynum' => $paynum, 'reasonnum' => $reasonnum, %options ); -} else { + } +} else { # run cash refund. my %hash = map { $_, scalar($cgi->param($_)) } fields('cust_refund'); diff --git a/httemplate/elements/header-popup.html b/httemplate/elements/header-popup.html index 906b1ee51..37402014b 100644 --- a/httemplate/elements/header-popup.html +++ b/httemplate/elements/header-popup.html @@ -34,6 +34,7 @@ Example: <SCRIPT SRC="<% $fsurl %>elements/printtofit.js"></SCRIPT> % } % } + <SCRIPT SRC="<% $fsurl %>elements/topreload.js"></SCRIPT> <% $head |n %> </HEAD> <BODY <% $etc |n %>> diff --git a/httemplate/elements/popup-topreload.html b/httemplate/elements/popup-topreload.html new file mode 100644 index 000000000..7a166f6de --- /dev/null +++ b/httemplate/elements/popup-topreload.html @@ -0,0 +1,17 @@ +<%doc> + +Example: + + <& /elements/popup-topreload, mt('Action completed') &> + +</%doc> +<& /elements/header-popup.html, encode_entities($message) &> + <SCRIPT TYPE="text/javascript"> + topreload(); + </SCRIPT> +<& /elements/footer-popup.html &> +<%init> + +my $message = shift; + +</%init>
\ No newline at end of file diff --git a/httemplate/elements/select-cust_phone.html b/httemplate/elements/select-cust_phone.html new file mode 100644 index 000000000..94cd41322 --- /dev/null +++ b/httemplate/elements/select-cust_phone.html @@ -0,0 +1,31 @@ +<SELECT NAME="<% $opt{'field_name'} %>" ID="<% $opt{'field_name'} %>"> + + <OPTION VALUE="" selected="selected">Select a phone number + +% foreach $p (@$phone_types) { + <OPTION VALUE="<% $phones_formatted{$p} %>"><% $p |h%> (<% $cust_phones->$p |h %>) +%} + +</SELECT> + +<%init> + +my %opt = @_; +my $cust_num = $opt{'cust_num'}; +my $phone_types = $opt{'phone_types'}; +my $format = $opt{'format'}; + +my $cust_phones = qsearchs('cust_main', { 'custnum' => $cust_num }) + or die 'unknown custnum' . $cust_num; + +my %phones_formatted = map { + $_ => format_phone_number($cust_phones->$_, $format) +} @$phone_types; + +sub format_phone_number { + my ($n, $f) = @_; + if ($f eq 'xxxxxxxxxx') { $n =~ s/-//g; } + return $n; +} + +</%init>
\ No newline at end of file diff --git a/httemplate/elements/select.html b/httemplate/elements/select.html index 59010c140..9dd4aec2c 100644 --- a/httemplate/elements/select.html +++ b/httemplate/elements/select.html @@ -41,7 +41,7 @@ % % } -</SELECT> +</SELECT> <% $opt{'post_field_label'} %> % } <%init> diff --git a/httemplate/elements/topreload.js b/httemplate/elements/topreload.js new file mode 100644 index 000000000..84faee05c --- /dev/null +++ b/httemplate/elements/topreload.js @@ -0,0 +1,6 @@ + window.topreload = function() { + if (window != window.top) { + window.top.location.reload(); + } + } +
\ No newline at end of file diff --git a/httemplate/elements/tr-select-cust_phone.html b/httemplate/elements/tr-select-cust_phone.html new file mode 100644 index 000000000..cf88392b0 --- /dev/null +++ b/httemplate/elements/tr-select-cust_phone.html @@ -0,0 +1,12 @@ + <TR> + <TD ALIGN="right"><% $opt{'label'} || 'Customer Phones' %></TD> + <TD> + <% include( '/elements/select-cust_phone.html', %opt ) %> + </TD> + </TR> + +<%init> + +my %opt = @_; + +</%init> diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html index 3b9bb2299..f25171fef 100755 --- a/httemplate/elements/tr-select-reason.html +++ b/httemplate/elements/tr-select-reason.html @@ -5,17 +5,22 @@ Example: include( '/elements/tr-select-reason.html', #required - 'field' => 'reasonnum', - 'reason_class' => 'C', # currently 'C', 'R', 'F', 'S' or 'X' - # for cancel, credit, refund, suspend or void credit + 'field' => 'reasonnum', # field name + 'reason_class' => 'C', # one of those in %FS::reason_type::class_name + 'label' => 'Your Label', # field display label #recommended 'cgi' => $cgi, #easiest way for things to be properly "sticky" on errors #optional - 'control_button' => 'element_name', #button to be enabled when a reason is - #selected + 'control_button' => 'element_name', #button to be enabled when a reason is + #selected 'id' => 'element_id', + 'hide_add' => '1', # setting this will hide the add new reason link, + # even if the user has access to add a new reason. + 'hide_onload' => '1', # setting this will hide reason select box on page load, + # allowing for it do be displayed later. + 'pre_options' => [ 0 => 'all'], # an array of pre options. Defaults to 0 => 'select reason...' #deprecated ways to keep things "sticky" on errors # (requires duplicate code in each using file to parse cgi params) @@ -68,24 +73,28 @@ Example: </SCRIPT> %# sadly can't just use add_inline here, as we have non-text fields + <& tr-select-table.html, - 'label' => 'Reason', + 'label' => $label, 'field' => $name, 'id' => $id, 'table' => 'reason', 'records' => \@reasons, + 'label_callback' => sub { my $reason = shift; + $reason->type . ' : ' . $reason->reason }, 'name_col' => 'label', 'disable_empty' => 1, - 'pre_options' => [ 0 => 'Select reason...' ], + 'pre_options' => \@pre_options, 'post_options' => \@post_options, 'curr_value' => $init_reason, 'onchange' => $id.'_changed()', + 'hide_onload' => $opt{'hide_onload'}, &> % # "add new reason" fields % # should be a <fieldset>, but that doesn't fit well into the table -% if ( $curuser->access_right($add_access_right) ) { +% if ( $curuser->access_right($add_access_right) && !$hide_addnew ) { <TR id="<% $id %>_new_fields"> <TD COLSPAN=2> <TABLE CLASS="inv" STYLE="text-align: left"> @@ -184,6 +193,8 @@ my %opt = @_; my $name = $opt{'field'}; my $class = $opt{'reason_class'}; +my $label = $opt{'label'} ? $opt{'label'} : 'Reason'; +my $hide_addnew = $opt{'hide_addnew'} ? $opt{'hide_addnew'} : ''; my $init_reason; if ( $opt{'cgi'} ) { @@ -195,6 +206,8 @@ if ( $opt{'cgi'} ) { my $id = $opt{'id'} || $name; $id =~ s/\./_/g; # for edit/part_event +my $label_id = $opt{'label_id'} || ''; + my $add_access_right; if ($class eq 'C') { $add_access_right = 'Add on-the-fly cancel reason'; @@ -222,10 +235,14 @@ my @reasons = qsearch({ ' ON (reason.reason_type = reason_type.typenum)', 'hashref' => { disabled => '' }, 'extra_sql' => " AND reason_type.class = '$class'", + 'order_by' => ' ORDER BY type, reason', }); +my @pre_options = ( 0 => 'Select reason...' ); +@pre_options = @{ $opt{'pre_options'} } if $opt{'pre_options'}; + my @post_options; -if ( $curuser->access_right($add_access_right) ) { +if ( $curuser->access_right($add_access_right) && !$hide_addnew ) { @post_options = ( -1 => 'Add new reason' ); } diff --git a/httemplate/elements/tr-td-label.html b/httemplate/elements/tr-td-label.html index 8125541c7..542f4559c 100644 --- a/httemplate/elements/tr-td-label.html +++ b/httemplate/elements/tr-td-label.html @@ -1,4 +1,12 @@ -<TR> +<%doc> + +Actually <TR> <TH> $label </TH> + +Note that this puts the 'label' argument into the document verbatim, with no +escaping or localization. + +</%doc> +<TR id="<% $opt{'id'} %>_row" <% $row_style %>> <TD ALIGN = "right" VALIGN = "<% $opt{'valign'} || 'top' %>" @@ -14,6 +22,8 @@ my $style = 'padding-top: 3px'; $style .= '; '. $opt{'cell_style'} if $opt{'cell_style'}; +my $row_style = 'style="visibility:collapse;"' if $opt{'hide_onload'}; + my $required = $opt{'required'} ? '<font color="#ff0000">*</font> ' : ''; </%init> diff --git a/httemplate/misc/bulk_suspend_pkg.cgi b/httemplate/misc/bulk_suspend_pkg.cgi new file mode 100644 index 000000000..e41ea2b1a --- /dev/null +++ b/httemplate/misc/bulk_suspend_pkg.cgi @@ -0,0 +1,94 @@ +<% include('/elements/header-popup.html', "Suspend Packages") %> + +% if ( $cgi->param('error') ) { + <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT> + <BR><BR> +% } + +<FORM ACTION="<% $p %>misc/process/bulk_suspend_pkg.cgi" METHOD=POST> + +%# some false laziness w/search/cust_pkg.cgi + +<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>"> +% for my $param ( +% qw( +% agentnum cust_status cust_main_salesnum salesnum custnum magic status +% custom pkgbatch zip reasonnum +% 477part 477rownum date +% report_option +% ), +% grep { /^location_\w+$/ || /^report_option_any/ } $cgi->param +% ) { + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>"> +% } +% +% for my $param (qw( censustract censustract2 ) ) { +% next unless grep { $_ eq $param } $cgi->param; + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>"> +% } +% +% for my $param (qw( pkgpart classnum refnum towernum )) { +% foreach my $value ($cgi->param($param)) { + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $value |h %>"> +% } +% } +% +% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { +% + <INPUT TYPE="hidden" NAME="<% $field %>_null" VALUE="<% $cgi->param("${field}_null") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_begin" VALUE="<% $cgi->param("${field}_begin") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_beginning" VALUE="<% $cgi->param("${field}_beginning") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_end" VALUE="<% $cgi->param("${field}_end") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_ending" VALUE="<% $cgi->param("${field}_ending") |h %>"> +% } + +<% ntable('#cccccc') %> + +% my $date_init = 0; + <& /elements/tr-input-date-field.html, { + 'name' => 'suspend_date', + 'value' => $date, + 'label' => mt("Suspend package on"), + 'format' => $date_format, + } &> +% $date_init = 1; + + <& /elements/tr-select-reason.html, + field => 'suspend_reasonnum', + reason_class => 'S', + &> + +% if ( $FS::CurrentUser::CurrentUser->access_right('Unsuspend customer package')) { + + <& /elements/tr-input-date-field.html, { + 'name' => 'suspend_resume_date', + 'value' => '', + 'label' => mt('Unsuspend on'), + 'format' => $date_format, + 'noinit' => $date_init, + } &> +% } + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Suspend Packages"> + +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +#use Date::Parse qw(str2time); +#<table style="background-color: #cccccc; border-spacing: 2; width: 100%"> + +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + +my $date = time; + +</%init>
\ No newline at end of file diff --git a/httemplate/misc/bulk_unsuspend_pkg.cgi b/httemplate/misc/bulk_unsuspend_pkg.cgi new file mode 100644 index 000000000..8fbc41841 --- /dev/null +++ b/httemplate/misc/bulk_unsuspend_pkg.cgi @@ -0,0 +1,66 @@ +<% include('/elements/header-popup.html', "Unsuspend Packages") %> + +% if ( $cgi->param('error') ) { + <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT> + <BR><BR> +% } + +<FORM ACTION="<% $p %>misc/process/bulk_unsuspend_pkg.cgi" METHOD=POST> + +%# some false laziness w/search/cust_pkg.cgi + +<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>"> +% for my $param ( +% qw( +% agentnum cust_status cust_main_salesnum salesnum custnum magic status +% custom pkgbatch zip reasonnum +% 477part 477rownum date +% report_option +% ), +% grep { /^location_\w+$/ || /^report_option_any/ } $cgi->param +% ) { + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>"> +% } +% +% for my $param (qw( censustract censustract2 ) ) { +% next unless grep { $_ eq $param } $cgi->param; + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>"> +% } +% +% for my $param (qw( pkgpart classnum refnum towernum )) { +% foreach my $value ($cgi->param($param)) { + <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $value |h %>"> +% } +% } +% +% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { +% + <INPUT TYPE="hidden" NAME="<% $field %>_null" VALUE="<% $cgi->param("${field}_null") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_begin" VALUE="<% $cgi->param("${field}_begin") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_beginning" VALUE="<% $cgi->param("${field}_beginning") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_end" VALUE="<% $cgi->param("${field}_end") |h %>"> + <INPUT TYPE="hidden" NAME="<% $field %>_ending" VALUE="<% $cgi->param("${field}_ending") |h %>"> +% } + +<% ntable('#cccccc') %> + + <TR> + <TD><INPUT TYPE="checkbox" NAME="confirm"></TD> + <TD>Confirm Unsuspend Packages</TD> + </TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" VALUE="Unsuspend Packages"> + +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +</%init> diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi index f3a31eb3b..7b56f2aa1 100644 --- a/httemplate/misc/download-batch.cgi +++ b/httemplate/misc/download-batch.cgi @@ -20,7 +20,16 @@ elsif ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) { $opt{'format'} = $1; } -my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } ); +my $credit_transactions = "EXISTS (SELECT 1 FROM cust_pay_batch WHERE batchnum = $batchnum AND paycode = 'C') AS arecredits"; +my $pay_batch = qsearchs({ 'select' => "*, $credit_transactions", + 'table' => 'pay_batch', + 'hashref' => { batchnum => $batchnum }, + }); die "Batch not found: '$batchnum'" if !$pay_batch; +if ($pay_batch->{Hash}->{arecredits}) { + my $export_format = "FS::pay_batch::".$opt{'format'}; + die "This format can not handle refunds." unless $export_format->can('can_handle_credits'); +} + </%init> diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index b8ba99705..1c22f8ffd 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -46,6 +46,7 @@ should be used to set msgnum or from/subject/html_body cgi params <INPUT TYPE="hidden" NAME="search" VALUE="<% encode_base64(nfreeze(\%search)) %>"> <INPUT TYPE="hidden" NAME="popup" VALUE="<% $popup %>"> <INPUT TYPE="hidden" NAME="url" VALUE="<% $url | h %>"> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% scalar($cgi->param('custnum')) |h %>"> % if ( $cgi->param('action') eq 'send' ) { @@ -55,13 +56,12 @@ should be used to set msgnum or from/subject/html_body cgi params <& /elements/progress-init.html, 'OneTrueForm', [ qw( search table from subject html_body text_body - msgnum to_contact_classnum ) ], + msgnum to_contact_classnum emailtovoice_contact custnum ) ], $process_url, $pdest, &> % } elsif ( $cgi->param('action') eq 'preview' ) { - <INPUT TYPE="hidden" NAME="to_contact_classnum" VALUE="<% join(',', @contact_classnum) %>"> <FONT SIZE="+2">Preview notice</FONT> @@ -71,6 +71,7 @@ should be used to set msgnum or from/subject/html_body cgi params <TABLE BGCOLOR="#cccccc" CELLSPACING=0> <INPUT TYPE="hidden" NAME="msgnum" VALUE="<% scalar($cgi->param('msgnum')) %>"> + <INPUT TYPE="hidden" NAME="emailtovoice_contact" VALUE="<% scalar $cgi->param('emailtovoice_contact') |h %>"> % if ( $msg_template ) { <% include('/elements/tr-fixed.html', 'label' => 'Template:', @@ -151,7 +152,11 @@ Template: &> <BR> % # select destination contact classes -Send to contacts: +<TABLE CELLSPACING=0 id="send_to_contacts_table"> +<TR> + <TD>Send to contacts:</TD> + <TD> + <div id="contactclassesdiv"> <& /elements/checkboxes.html, 'style' => 'display: inline; vertical-align: top', 'disable_links' => 1, @@ -162,6 +167,24 @@ Send to contacts: $name eq 'invoice' #others default to unchecked }, &> + </div> +% if ($send_to_domain) { + <div> + <INPUT TYPE="checkbox" NAME="emailtovoice" ID="emailtovoice" VALUE="ON" onclick="toggleDiv(this)">Email to voice + </div> + <div id="emailtovoicediv" style="display:none"> + + <& /elements/select-cust_phone.html, + 'cust_num' => $cgi->param('custnum'), + 'field_name' => 'emailtovoice_contact', + 'format' => 'xxxxxxxxxx', + 'phone_types' => [ 'daytime', 'night', 'fax', 'mobile' ], + &>@<% $send_to_domain |h %> + </div> +% } + </TD> +</TR> +</TABLE> <BR> % # if sending a one-off message, show a form to edit it <TABLE BGCOLOR="#cccccc" CELLSPACING=0 WIDTH="100%" id="table_no_template"> @@ -199,6 +222,7 @@ Send to contacts: %#Substitution vars: <INPUT TYPE="hidden" NAME="action" VALUE="preview"> + <INPUT TYPE="hidden" NAME="custnum" VALUE="<% scalar($cgi->param('custnum')) |h %>"> <INPUT TYPE="submit" VALUE="Preview notice"> % } #end not action or alternate form @@ -211,6 +235,18 @@ Send to contacts: </SCRIPT> % } +<SCRIPT TYPE="text/javascript"> +function toggleDiv(obj) { + var box_contactclasses = document.getElementById('contactclassesdiv'); + var box_emailtovoice = document.getElementById('emailtovoicediv'); + + box_emailtovoice.style.display = (box_emailtovoice.style.display == 'none') ? 'block' : 'none'; + document.getElementById('emailtovoice_contact').options[0].selected=true; + + box_contactclasses.style.display = (box_contactclasses.style.display == 'none') ? 'block' : 'none'; +} +</SCRIPT> + <& /elements/footer.html &> <%init> @@ -219,12 +255,16 @@ my %opt = @_; $opt{'acl'} ||= 'Bulk send customer notices'; +my $email_to; + die "access denied" unless $FS::CurrentUser::CurrentUser->access_right($opt{'acl'}); my $conf = FS::Conf->new; my @no_search_fields = qw( action table from subject html_body text_body popup url ); +my $send_to_domain = $conf->config('email-to-voice_domain'); + my $form_action = $opt{'form_action'} || 'email-customers.html'; my $process_url = $opt{'process_url'} || 'process/email-customers.html'; my $title = $opt{'title'} || 'Send customer notices'; @@ -237,6 +277,7 @@ my $agent_virt_agentnum = $cgi->param('agent_virt_agentnum') || ''; my $popup = $cgi->param('popup'); my $url = $cgi->param('url'); +if (!$url && $cgi->param('custnum')) { $url = $fsurl."view/cust_main.cgi?".$cgi->param('custnum'); } my $pdest = { 'message' => "Notice sent" }; $pdest->{'url'} = $cgi->param('url') if $url; @@ -307,19 +348,40 @@ if ( $cgi->param('action') eq 'preview' ) { my %message = $msg_template->prepare(%msgopts); ($from, $subject, $html_body) = @message{'from', 'subject', 'html_body'}; } +} + +if ($cgi->param('action')) { # contact_class_X params in preview - foreach my $param ( $cgi->param ) { - if ( $param =~ /^contact_class_(\w+)$/ ) { - push @contact_classnum, $1; - if ( $1 eq 'invoice' ) { + if ($cgi->param('emailtovoice_contact')) { + $email_to = $cgi->param('emailtovoice_contact') . '@' . $send_to_domain; + push @contact_classnum, 'emailtovoice'; + push @contact_classname, $email_to; + } + elsif ($cgi->param('to_contact_classnum')) { + foreach my $c (split(/,/, $cgi->param('to_contact_classnum'))) { + push @contact_classnum, $c; + if ( $c eq 'invoice' ) { push @contact_classname, 'Invoice recipients'; } else { - my $contact_class = FS::contact_class->by_key($1); + my $contact_class = FS::contact_class->by_key($c); push @contact_classname, encode_entities($contact_class->classname); } } } + else { + foreach my $param ( $cgi->param ) { + if ( $param =~ /^contact_class_(\w+)$/ ) { + push @contact_classnum, $1; + if ( $1 eq 'invoice' ) { + push @contact_classname, 'Invoice recipients'; + } else { + my $contact_class = FS::contact_class->by_key($1); + push @contact_classname, encode_entities($contact_class->classname); + } + } + } + } } @@ -327,10 +389,12 @@ if ( $cgi->param('action') eq 'preview' ) { my @contact_checkboxes = ( [ 'invoice' => { label => 'Invoice recipients' } ] ); + foreach my $class (qsearch('contact_class', { disabled => '' })) { push @contact_checkboxes, [ $class->classnum, { label => $class->classname } ]; } + </%init> diff --git a/httemplate/misc/process/bulk_suspend_pkg.cgi b/httemplate/misc/process/bulk_suspend_pkg.cgi new file mode 100644 index 000000000..2ac9c212f --- /dev/null +++ b/httemplate/misc/process/bulk_suspend_pkg.cgi @@ -0,0 +1,106 @@ +% if ($error) { +<% $cgi->redirect(popurl(2)."bulk_suspend_pkg.cgi?".$cgi->query_string ) %> +% } +<% include('/elements/popup-topreload.html', "Packages Suspended") %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +my $error; + +if (!$error) { + + my %search_hash = (); + + $search_hash{'query'} = $cgi->param('query'); + + #scalars + for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status + custom cust_fields pkgbatch zip reasonnum + 477part 477rownum date + )) + { + $search_hash{$_} = $cgi->param($_) if length($cgi->param($_)); + } + + #arrays + for my $param (qw( pkgpart classnum refnum towernum )) { + $search_hash{$param} = [ $cgi->param($param) ] + if grep { $_ eq $param } $cgi->param; + } + + #scalars that need to be passed if empty + for my $param (qw( censustract censustract2 )) { + $search_hash{$param} = $cgi->param($param) || '' + if grep { $_ eq $param } $cgi->param; + } + + #location flags (checkboxes) + my @loc = grep /^\w+$/, $cgi->param('loc'); + $search_hash{"location_$_"} = 1 foreach @loc; + + my $report_option = $cgi->param('report_option'); + $search_hash{report_option} = $report_option if $report_option; + + for my $param (grep /^report_option_any/, $cgi->param) { + $search_hash{$param} = $cgi->param($param); + } + + ### + # parse dates + ### + + #false laziness w/report_cust_pkg.html and bulk_pkg_increment_bill.cgi + my %disable = ( + 'all' => {}, + 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, + 'active' => { 'susp'=>1, 'cancel'=>1 }, + 'suspended' => { 'cancel' => 1 }, + 'cancelled' => {}, + '' => {}, + ); + + foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { + + $search_hash{$field.'_null'} = scalar( $cgi->param($field.'_null') ); + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); + + next if $beginning == 0 && $ending == 4294967295 + or $disable{$cgi->param('status')}->{$field}; + + $search_hash{$field} = [ $beginning, $ending ]; + + } + + my $sql_query = FS::cust_pkg->search(\%search_hash); + $sql_query->{'select'} = 'cust_pkg.pkgnum'; + + ## set suspend info + $cgi->param('suspend_reasonnum') =~ /^(\d+)$/ or die "Illegal Reason"; + my $suspend_reasonnum = $1; + + my $suspend_date = time; + parse_datetime($cgi->param('suspend_date')) =~ /^(\d+)$/ or die "Illegal date"; + $suspend_date = $1; + + my $suspend_resume_date = ''; + (parse_datetime($cgi->param('suspend_resume_date')) =~ /^(\d+)$/ or die "Illegal resume date") if $cgi->param('suspend_resume_date'); + $suspend_resume_date = $1; + + foreach my $pkgnum (map { $_->pkgnum } qsearch($sql_query)) { + my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + + $error = $cust_pkg->suspend('reason' => $suspend_reasonnum, + 'date' => $suspend_date, + 'resume_date' => $suspend_resume_date, + ); + } + +} + +$cgi->param("error", substr($error, 0, 512)); # arbitrary length believed + # suited for all supported + # browsers +</%init>
\ No newline at end of file diff --git a/httemplate/misc/process/bulk_unsuspend_pkg.cgi b/httemplate/misc/process/bulk_unsuspend_pkg.cgi new file mode 100644 index 000000000..13389f43a --- /dev/null +++ b/httemplate/misc/process/bulk_unsuspend_pkg.cgi @@ -0,0 +1,91 @@ +% if ($error) { +<% $cgi->redirect(popurl(2)."bulk_unsuspend_pkg.cgi?".$cgi->query_string ) %> +% } +<% include('/elements/popup-topreload.html', "Packages Unsuspended") %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +my $error; +$error = 'Unsuspend packages not confirmed' if !$cgi->param('confirm'); + +if (!$error) { + + my %search_hash = (); + + $search_hash{'query'} = $cgi->param('query'); + + #scalars + for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status + custom cust_fields pkgbatch zip reasonnum + 477part 477rownum date + )) + { + $search_hash{$_} = $cgi->param($_) if length($cgi->param($_)); + } + + #arrays + for my $param (qw( pkgpart classnum refnum towernum )) { + $search_hash{$param} = [ $cgi->param($param) ] + if grep { $_ eq $param } $cgi->param; + } + + #scalars that need to be passed if empty + for my $param (qw( censustract censustract2 )) { + $search_hash{$param} = $cgi->param($param) || '' + if grep { $_ eq $param } $cgi->param; + } + + #location flags (checkboxes) + my @loc = grep /^\w+$/, $cgi->param('loc'); + $search_hash{"location_$_"} = 1 foreach @loc; + + my $report_option = $cgi->param('report_option'); + $search_hash{report_option} = $report_option if $report_option; + + for my $param (grep /^report_option_any/, $cgi->param) { + $search_hash{$param} = $cgi->param($param); + } + + ### + # parse dates + ### + + #false laziness w/report_cust_pkg.html and bulk_pkg_increment_bill.cgi + my %disable = ( + 'all' => {}, + 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, + 'active' => { 'susp'=>1, 'cancel'=>1 }, + 'suspended' => { 'cancel' => 1 }, + 'cancelled' => {}, + '' => {}, + ); + + foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { + + $search_hash{$field.'_null'} = scalar( $cgi->param($field.'_null') ); + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); + + next if $beginning == 0 && $ending == 4294967295 + or $disable{$cgi->param('status')}->{$field}; + + $search_hash{$field} = [ $beginning, $ending ]; + + } + + my $sql_query = FS::cust_pkg->search(\%search_hash); + $sql_query->{'select'} = 'cust_pkg.pkgnum'; + + foreach my $pkgnum (map { $_->pkgnum } qsearch($sql_query)) { + my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + $error = $cust_pkg->unsuspend; + } + +} + +$cgi->param("error", substr($error, 0, 512)); # arbitrary length believed + # suited for all supported + # browsers +</%init>
\ No newline at end of file diff --git a/httemplate/misc/process/contact-import.cgi b/httemplate/misc/process/contact-import.cgi index cbdcad455..108ee93e9 100644 --- a/httemplate/misc/process/contact-import.cgi +++ b/httemplate/misc/process/contact-import.cgi @@ -5,6 +5,6 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Import'); my $server = - new FS::UI::Web::JSRPC 'FS::contact_import::process_batch_import', $cgi; + new FS::UI::Web::JSRPC 'FS::contact::Import::process_batch_import', $cgi; </%init> diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index 2459c44b2..3eb0332d2 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -159,7 +159,7 @@ $search_hash{'query'} = $cgi->keywords; #scalars for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status - custom cust_fields pkgbatch zip + reasonnum custom cust_fields pkgbatch zip 477part 477rownum date )) { @@ -270,6 +270,22 @@ my $html_init = sub { 'height' => 210, ). '<BR>'; + $text .= include( '/elements/popup_link.html', + 'label' => emt('Suspend these packages'), + 'action' => "${p}misc/bulk_suspend_pkg.cgi?$query", + 'actionlabel' => emt('Suspend Packages'), + 'width' => 569, + 'height' => 210, + ). '<BR>' if $search_hash{status} eq 'active'; + + $text .= include( '/elements/popup_link.html', + 'label' => emt('Unsuspend these packages'), + 'action' => "${p}misc/bulk_unsuspend_pkg.cgi?$query", + 'actionlabel' => emt('Unsuspend Packages'), + 'width' => 569, + 'height' => 210, + ). '<BR>' if $search_hash{status} eq 'suspended'; + if ( $curuser->access_right('Edit customer package dates') ) { $text .= include( '/elements/popup_link.html', 'label' => emt('Increment next bill date'), diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html index ed5af2481..8c910e603 100755 --- a/httemplate/search/report_cust_pkg.html +++ b/httemplate/search/report_cust_pkg.html @@ -67,10 +67,29 @@ 'onchange' => 'status_changed(this);', &> + <& /elements/tr-select-reason.html, + 'field' => 'reasonnum', + 'reason_class' => 'S', + 'label' => 'Suspended Reason', + 'label_id' => 'reasonnum_label', + 'hide_addnew' => '1', + 'hide_onload' => '1', + 'cgi' => $cgi, + 'control_button' => 'confirm_suspend_cust_button', + 'pre_options' => [ 0 => 'all' ], + &> + <SCRIPT TYPE="text/javascript"> function status_changed(what) { + if (what.options[what.selectedIndex].value == 'suspended') { + document.getElementById('reasonnum_row').style.visibility = 'visible'; + } + else { + document.getElementById('reasonnum_row').style.visibility = 'collapse'; + } + % foreach my $status ( '', FS::cust_pkg->statuses() ) { if ( what.options[what.selectedIndex].value == '<% $status %>' ) { |
