diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-10-13 10:10:40 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-10-13 10:10:40 -0700 |
commit | 2b2dd969f3c18751afc583ad1e836ab8e6f73b5d (patch) | |
tree | 72ad19092f9d3a5118add9a55067b8a97c168f46 /httemplate/misc | |
parent | d31d59c63c8f4dfd52ca19a02ffcf32fcf49f497 (diff) | |
parent | cd468ecb9a321ca96254b7204f6dc193b11cd903 (diff) |
Merge branch 'master' of git.freeside.biz:/home/git/freeside
Diffstat (limited to 'httemplate/misc')
-rw-r--r-- | httemplate/misc/batch-cust_pay.html | 97 | ||||
-rwxr-xr-x | httemplate/misc/change_pkg.cgi | 23 | ||||
-rw-r--r-- | httemplate/misc/cust_pkg_usageprice.html | 121 | ||||
-rwxr-xr-x | httemplate/misc/delete-cust_credit.cgi | 21 | ||||
-rwxr-xr-x | httemplate/misc/delete-cust_pay.cgi | 21 | ||||
-rw-r--r-- | httemplate/misc/email-customers.html | 220 | ||||
-rw-r--r-- | httemplate/misc/order_pkg.html | 21 | ||||
-rw-r--r-- | httemplate/misc/process/deploy_zone-block_lookup.cgi | 13 | ||||
-rw-r--r-- | httemplate/misc/process/payment.cgi | 82 | ||||
-rw-r--r-- | httemplate/misc/process/send-report.html | 7 | ||||
-rw-r--r-- | httemplate/misc/process/template_image-delete.cgi | 28 | ||||
-rw-r--r-- | httemplate/misc/process/template_image-upload.cgi | 26 | ||||
-rwxr-xr-x | httemplate/misc/process/void-cust_bill.html | 2 | ||||
-rw-r--r-- | httemplate/misc/send-report.html | 166 | ||||
-rwxr-xr-x | httemplate/misc/unapply-cust_pay.cgi | 6 | ||||
-rw-r--r-- | httemplate/misc/void-cust_bill.html | 2 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-part_pkg_usageprice.html | 18 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-template_image.cgi | 48 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-ticket-update.html | 66 |
19 files changed, 761 insertions, 227 deletions
diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index 9f2540cc7..197ade14f 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -101,6 +101,10 @@ function select_discount_term(row) { var invoices_for_row = new Object; +var preloading = 0; // the number of preloading threads currently running + +// callback from toggle_application_row: we've received a list of +// the customer's open invoices. store them. function update_invoices(rownum, invoices) { invoices_for_row[rownum] = new Object; // only called before create_application_row @@ -113,6 +117,12 @@ function toggle_application_row(ev, next) { if (!next) next = function(){}; //optional continuation var rownum = this.getAttribute('rownum'); if ( this.checked ) { + // the user has opted to apply the payment to specific invoices. + // - lock the customer + // - fetch the list of open invoices + // - create a row to select an invoice + // - then optionally call "next", with this as the invocant + // and the rownum as argument; we use this to preload rows. var custnum = document.getElementById('custnum'+rownum).value; if (!custnum) return; lock_payment_row(rownum, true); @@ -124,6 +134,9 @@ function toggle_application_row(ev, next) { } ); } else { + // the user has opted not to do that. + // - remove all application rows + // - unlock the customer var row = document.getElementById('row'+rownum); var table_rows = row.parentNode.rows; for (i = row.sectionRowIndex; i < table_rows.count; i++) { @@ -183,6 +196,16 @@ function amount_unapplied(rownum) { var change_app_amount; +// the user has chosen an invoice. the previously chosen invoice is still +// in curr_invoice +// - if there is a value there, put it back on the invoices_for_row list for +// this customer. +// - then _remove_ the newly chosen invoice from that list. +// - find the "owed" element for this application row and set its value to the +// amount owed on that invoice. +// - find the "amount" element for this application row and set its value to +// either "owed" or the remaining payment amount, whichever is less. +// - call change_app_amount() on that element. function choose_app_invnum() { var rownum = this.getAttribute('rownum'); var appnum = this.getAttribute('appnum'); @@ -210,8 +233,10 @@ function choose_app_invnum() { } } +// the invoice selector has gained focus. clear its list of options, and +// replace them with the list of open invoices (from invoices_for_row). +// if there's already a selected invoice, prepend that to the list. function focus_app_invnum() { -% # invoice numbers just display as invoice numbers var rownum = this.getAttribute('rownum'); var add_opt = function(obj, value, label) { var o = document.createElement('OPTION'); @@ -233,14 +258,15 @@ function focus_app_invnum() { } } +// an application amount has been changed. if there's any unapplied payment +// amount, and any remaining invoices_for_row, add a blank application row. +// (but don't do this while preloading; it will unconditionally add enough +// rows to show all the attempted applications) function change_app_amount() { var rownum = this.getAttribute('rownum'); var appnum = this.getAttribute('appnum'); -%# maybe some kind of warning if amount_unapplied < 0? -%# only spawn a new application row if there are open invoices left, -%# and this is the highest-numbered application row for the customer, -%# and the sum of the applied amounts is < the amount of the payment, - if ( Object.keys(invoices_for_row[rownum]).length > 0 + if ( preloading == 0 + && Object.keys(invoices_for_row[rownum]).length > 0 && !document.getElementById( 'row'+rownum+'.'+(parseInt(appnum) + 1) ) && amount_unapplied(rownum) > 0 ) { @@ -248,6 +274,9 @@ function change_app_amount() { } } +// we're creating a payment application row. +// create the following elements: <TR>, <TD>s, "Apply to invoice" caption, +// invnum selector, "owed" display, amount input box, delete button. function create_application_row(rownum, appnum) { var payment_row = document.getElementById('row'+rownum); var tr_app = document.createElement('TR'); @@ -341,29 +370,45 @@ function preload() { var enable = document.getElementById('enable_app'+rownum); enable.checked = true; var preload_row = function(r) {//continuation from toggle_application_row - for (appnum=0; appnum < row_obj[r].length; appnum++) { - this_app = row_obj[r][appnum]; - var x = r + '.' + appnum; - //set invnum - var select_invnum = document.getElementById('invnum'+x); - focus_app_invnum.call(select_invnum); - for (i=0; i<select_invnum.options.length; i++) { - if (select_invnum.options[i].value == this_app.invnum) { - select_invnum.selectedIndex = i; + + preloading++; + + try { + for (appnum=0; appnum < row_obj[r].length; appnum++) { + this_app = row_obj[r][appnum]; + var x = r + '.' + appnum; + //set invnum + var select_invnum = document.getElementById('invnum'+x); + focus_app_invnum.call(select_invnum); + for (i=0; i<select_invnum.options.length; i++) { + if (select_invnum.options[i].value == this_app.invnum) { + select_invnum.selectedIndex = i; + } } - } - choose_app_invnum.call(select_invnum); - //set amount - var input_amount = document.getElementById('amount'+x); - input_amount.value = this_app.amount; - - //set error - var span_error = document.getElementById('error'+x); - span_error.innerHTML = this_app.error; - change_app_amount.call(input_amount); //creates next row - } //for appnum + choose_app_invnum.call(select_invnum); + //set amount + var input_amount = document.getElementById('amount'+x); + input_amount.value = this_app.amount; + + //set error + var span_error = document.getElementById('error'+x); + span_error.innerHTML = this_app.error; + + // create another row (unconditionally) + create_application_row(r, appnum + 1); + + } //for appnum + + } finally { + preloading--; + } + }; //preload_row function + + // enable application rows on the selected customer. this creates + // the first row, then kicks off preloading. toggle_application_row.call(enable, null, preload_row); + } // if (row_obj[rownum].length } //for rownum } diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi index e74747e82..b562d24cd 100755 --- a/httemplate/misc/change_pkg.cgi +++ b/httemplate/misc/change_pkg.cgi @@ -19,13 +19,13 @@ <& /elements/tr-select-cust-part_pkg.html, 'pre_label' => emt('New'), - 'curr_value' => scalar($cgi->param('pkgpart')), + 'curr_value' => scalar($cgi->param('pkgpart')) || $cust_pkg->pkgpart, 'classnum' => $part_pkg->classnum, 'cust_main' => $cust_main, &> <& /elements/tr-input-pkg-quantity.html, - 'curr_value' => $cust_pkg->quantity + 'curr_value' => scalar($cgi->param('quantity')) || $cust_pkg->quantity &> % if ($use_contract_end) { @@ -39,6 +39,11 @@ </TABLE> <BR> +<% include('/misc/cust_pkg_usageprice.html', + 'pkgpart' => (scalar($cgi->param('pkgpart')) || $cust_pkg->pkgpart), + 'pkgnum' => ($cust_pkg->change_to_pkgnum || $pkgnum), + ) %> +<BR> <FONT CLASS="fsinnerbox-title"><% mt('Change') |h %></FONT> <% ntable('#cccccc') %> @@ -49,8 +54,16 @@ document.getElementById('start_date_text').disabled = !enable; document.getElementById('start_date_button').style.display = (enable ? '' : 'none'); - document.getElementById('start_date_button_disabled').style.display = - (enable ? 'none' : ''); + if (document.getElementById('start_date_button_disabled')) { // does this ever exist anymore? + document.getElementById('start_date_button_disabled').style.display = + (enable ? 'none' : ''); + } + if (enable) { + usageprice_disable(1); + } else { + var form = document.OrderPkgForm; + usageprice_disable(0,form.pkgpart.options[form.pkgpart.selectedIndex].value); + } } <&| /elements/onload.js &> delay_changed(); @@ -96,7 +109,7 @@ TYPE = "button" VALUE = "<% mt("Change package") |h %>" onClick = "this.disabled=true; standardize_new_location();" - <% scalar($cgi->param('pkgpart')) ? '' : 'DISABLED' %> + <% #scalar($cgi->param('pkgpart')) ? '' : 'DISABLED' %> > </FORM> diff --git a/httemplate/misc/cust_pkg_usageprice.html b/httemplate/misc/cust_pkg_usageprice.html new file mode 100644 index 000000000..f2e0f57e6 --- /dev/null +++ b/httemplate/misc/cust_pkg_usageprice.html @@ -0,0 +1,121 @@ +<%doc> +Sets up the xmlhttp, javascript and initial (empty) table for selecting cust_pkg_usageprice. +Available values are based on pkgpart, and can be updated when changing pkgpart +by passing the new pkgpart to the following javascript: + + usageprice_pkg_changed( pkgpart, pkgnum ) + +The pkgnum input is optional, and will be used to set initial selected values. + +If pkgpart is passed as an option to this element, will run usageprice_pkg_changed +once to initialize table; pkgnum can be passed as an option along with this. + +You can disable usageprice selection temporarily (remove the fields from the form) +with the javascript usageprice_disable(1), and restore it with usageprice_disable(0,pkgnum). +While disabled, calling usageprice_pkg_changed will have no effect. +</%doc> + +<& /elements/xmlhttp.html, + 'url' => $p.'misc/xmlhttp-part_pkg_usageprice.html', + 'subs' => [ 'get_part_pkg_usageprice' ], +&> + +<FONT CLASS = "fsinnerbox-title" + ID = "cust_pkg_usageprice_title" + STYLE = "display:none" +><% mt('Usage add-ons') |h %></FONT> +<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 ID="cust_pkg_usageprice_table"> + +</TABLE> + +<SCRIPT> + +var usagepriceCache = {}; +var usagepriceDisabled = 0; + +function usageprice_disable (disabled, pkgpart) { + if (disabled) { + usageprice_pkg_changed(0); + usagepriceDisabled = 1; + } else { + usagepriceDisabled = 0; + usageprice_pkg_changed(pkgpart); + } +} + +// main function to invoke when pkgpart changes +function usageprice_pkg_changed (pkgpart, pkgnum) { + if (usagepriceDisabled) return; + clear_part_pkg_usageprice(); + + if (pkgpart) { + if (usagepriceCache[pkgpart]) { + update_part_pkg_usageprice(pkgpart); + } else { + get_part_pkg_usageprice( pkgpart || 0, pkgnum || 0, download_part_pkg_usageprice ); + } + } +} + +// removes table rows & hides table title +function clear_part_pkg_usageprice () { + var table = document.getElementById('cust_pkg_usageprice_table'); + for ( var r = table.rows.length - 1; r >= 0; r-- ) { + table.deleteRow(r); + } + document.getElementById('cust_pkg_usageprice_title').style.display = 'none'; +} + +// catches response from xmlhttp request, updates cache & calls update function +function download_part_pkg_usageprice (part_pkg_usageprice) { + var usagepriceArray = JSON.parse(part_pkg_usageprice); + var pkgpart = usagepriceArray[0]; + usagepriceCache[pkgpart] = usagepriceArray; + update_part_pkg_usageprice(pkgpart); +} + +// updates from cache +function update_part_pkg_usageprice (pkgpart) { + if (usagepriceDisabled) return; + clear_part_pkg_usageprice(); + + var usagepriceArray = usagepriceCache[pkgpart]; + var table = document.getElementById('cust_pkg_usageprice_table'); + + // add the new usage price rows + var rownum = 0; + for ( var s = 1; s < usagepriceArray.length; s=s+2 ) { + var html = usagepriceArray[s]; + var javascript = usagepriceArray[s+1]; + + var row = table.insertRow(rownum++); + + var widget_cell = document.createElement('TD'); + widget_cell.style.paddingTop = "3px"; + widget_cell.colSpan = "2"; + widget_cell.innerHTML = html; + row.appendChild(widget_cell); + + } + + if ( rownum > 0 ) { + document.getElementById('cust_pkg_usageprice_title').style.display = ''; + } else { + document.getElementById('cust_pkg_usageprice_title').style.display = 'none'; + } + +} + +% if ($opt{'pkgpart'}) { +<&| /elements/onload.js &> +usageprice_pkg_changed(<% $opt{'pkgpart'} %>, <% $opt{'pkgnum'} %>); +</&> +% } + +</SCRIPT> + +<%init> +my %opt = @_; +</%init> + + diff --git a/httemplate/misc/delete-cust_credit.cgi b/httemplate/misc/delete-cust_credit.cgi deleted file mode 100755 index 03eb47299..000000000 --- a/httemplate/misc/delete-cust_credit.cgi +++ /dev/null @@ -1,21 +0,0 @@ -% if ( $error ) { -% errorpage($error); -% } else { -<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> -% } -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Delete credit'); - -#untaint crednum -my($query) = $cgi->keywords; -$query =~ /^(\d+)$/ || die "Illegal crednum"; -my $crednum = $1; - -my $cust_credit = qsearchs('cust_credit',{'crednum'=>$crednum}); -my $custnum = $cust_credit->custnum; - -my $error = $cust_credit->delete; - -</%init> diff --git a/httemplate/misc/delete-cust_pay.cgi b/httemplate/misc/delete-cust_pay.cgi deleted file mode 100755 index 38e7e4ba1..000000000 --- a/httemplate/misc/delete-cust_pay.cgi +++ /dev/null @@ -1,21 +0,0 @@ -% if ( $error ) { -% errorpage($error); -% } else { -<% $cgi->redirect($p. "view/cust_main.cgi?". $custnum) %> -% } -<%init> - -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Delete payment'); - -#untaint paynum -my($query) = $cgi->keywords; -$query =~ /^(\d+)$/ || die "Illegal paynum"; -my $paynum = $1; - -my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum}); -my $custnum = $cust_pay->custnum; - -my $error = $cust_pay->delete; - -</%init> diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index 47e6a5b48..8e2863455 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -1,10 +1,11 @@ <%doc> -Allows emailing one or more customers, based on a search for customers. Search can -be specified either through cust_main fields as cgi params, or through a base64 encoded -frozen hash in the 'search' cgi param. Form allows selecting an existing msg_template, -or creating a custom message, and shows a preview of the message before sending. -If linked to as a popup, include the cgi parameter 'popup' for proper header handling. +Allows emailing one or more customers, based on a search for customers. +Search can be specified either through cust_main fields as cgi params, or +through a base64 encoded frozen hash in the 'search' cgi param. Form allows +selecting an existing msg_template, or creating a custom message, and shows a +preview of the message before sending. If linked to as a popup, include the +cgi parameter 'popup' for proper header handling. This may also be used as an element in other pages, enabling you to provide an alternate initial form while using this for search freezing/thawing and @@ -21,12 +22,13 @@ title - the title of the page no_search_fields - arrayref of additional fields that are not search parameters alternate_form - subroutine that returns alternate html for the initial form, -replaces msgnum/from/subject/html_body/action inputs and submit button, -not used if an action is specified +replaces msgnum/from/subject/body/action inputs and submit button, not +used if an action is specified -post_search_hook - sub hook for additional processing after search has been processed from cgi, -gets passed options 'conf' and 'search' (a reference to the unfrozen %search hash), -should be used to set msgnum or from/subject/html_body cgi params +post_search_hook - sub hook for additional processing after search has been +processed from cgi, gets passed options 'conf' and 'search' (a reference to +the unfrozen %search hash), should be used to set msgnum or +from/subject/body cgi params </%doc> % if ($popup) { @@ -35,8 +37,9 @@ should be used to set msgnum or from/subject/html_body cgi params <& /elements/header.html, $title &> % } +<& /elements/error.html &> -<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="GET"> +<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="POST"> <INPUT TYPE="hidden" NAME="table" VALUE="<% $table %>"> %# Mixing search params with from address, subject, etc. required special-case %# handling of those, risked name conflicts, and caused massive problems with @@ -46,48 +49,40 @@ should be used to set msgnum or from/subject/html_body cgi params <INPUT TYPE="hidden" NAME="popup" VALUE="<% $popup %>"> <INPUT TYPE="hidden" NAME="url" VALUE="<% $url | h %>"> -% if ( $cgi->param('action') eq 'send' ) { - - <FONT SIZE="+2">Sending notice</FONT> +% if ( $cgi->param('preview') ) { +% # preview mode: at this point we have a msg_template (either "real" or +% # draft) and $html_body and $text_body contain the preview message. +% # give the user a chance to back out (by going back to edit mode). + <FONT SIZE="+2">Preview notice</FONT> <& /elements/progress-init.html, 'OneTrueForm', - [ qw( search table from subject html_body text_body msgnum ) ], + [ qw( search table msgnum ) ], $process_url, $pdest, &> -% } elsif ( $cgi->param('action') eq 'preview' ) { - - <FONT SIZE="+2">Preview notice</FONT> - -% } - -% if ( $cgi->param('action') ) { - <TABLE CLASS="fsinnerbox"> - <INPUT TYPE="hidden" NAME="msgnum" VALUE="<% scalar($cgi->param('msgnum')) %>"> - -% if ( $msg_template ) { - <& /elements/tr-fixed.html, - 'label' => 'Template:', - 'value' => $msg_template->msgname, - &> -% } + <INPUT TYPE="hidden" NAME="msgnum" VALUE="<% $msg_template->msgnum %>"> +% # kludge these through hidden inputs because they're not really part +% # of the template, but should be sticky during draft editing + <INPUT TYPE="hidden" NAME="from_name" VALUE="<% $cgi->param('from_name') %>"> + <INPUT TYPE="hidden" NAME="from_addr" VALUE="<% $cgi->param('from_addr') %>"> + +% if ( !$msg_template->disabled ) { + <& /elements/tr-td-label.html, 'label' => 'Template:' &> + <td><% $msg_template->msgname |h %></td> + </tr> +% } - <& /elements/tr-fixed.html, - 'field' => 'from', - 'label' => 'From:', - 'value' => $from, - &> + <& /elements/tr-td-label.html, 'label' => 'From:' &> + <td><% $from |h %></td> + </tr> - <& /elements/tr-fixed.html, - 'field' => 'subject', - 'label' => 'Subject:', - 'value' => $subject, - &> + <& /elements/tr-td-label.html, 'label' => 'Subject:' &> + <td><% $subject |h %></td> + </tr> - <INPUT TYPE="hidden" NAME="html_body" VALUE="<% $html_body |h %>"> <TR><TD COLSPAN=2> </TD></TR> <TR> <TH ALIGN="right" VALIGN="top">Message (HTML display): </TD> @@ -99,7 +94,6 @@ should be used to set msgnum or from/subject/html_body cgi params % $html_body % ) % ); - <INPUT TYPE="hidden" NAME="text_body" VALUE="<% $text_body |h %>"> <TR><TD COLSPAN=2> </TD></TR> <TR> <TH ALIGN="right" VALIGN="top">Message (Text display): </TD> @@ -112,38 +106,37 @@ should be used to set msgnum or from/subject/html_body cgi params </TABLE> -% if ( $cgi->param('action') eq 'preview' ) { + <SCRIPT> - <SCRIPT> - - function showtext() { - $('#email-message-text-view').css('display','none'); - $('#email-message-text-hide').css('display',''); - $('#email-message-text').slideDown(); - } + function showtext() { + $('#email-message-text-view').css('display','none'); + $('#email-message-text-hide').css('display',''); + $('#email-message-text').slideDown(); + } - function hidetext() { - $('#email-message-text-view').css('display',''); - $('#email-message-text-hide').css('display','none'); - $('#email-message-text').slideUp(); - } + function hidetext() { + $('#email-message-text-view').css('display',''); + $('#email-message-text-hide').css('display','none'); + $('#email-message-text').slideUp(); + } - function areyousure(href) { - return confirm("Send this notice to <% ($num_cust > 1) ? "$num_cust customers" : '1 customer' %> ?"); + function areyousure(href) { + if (confirm("Send this notice to <% ($num_cust > 1) ? "$num_cust customers" : '1 customer' %> ?")) { + process(); } - </SCRIPT> + } + </SCRIPT> - <BR> - <INPUT TYPE="hidden" NAME="action" VALUE="send"> - <INPUT TYPE="submit" VALUE="Send notice" onClick="return areyousure()"> - -% } + <BR> + <INPUT TYPE="submit" NAME="edit" VALUE="Edit"> + <INPUT TYPE="button" VALUE="Send notice" onClick="areyousure()"> % } elsif ($opt{'alternate_form'}) { <% &{$opt{'alternate_form'}}() %> % } else { +% # Edit mode. <SCRIPT TYPE="text/javascript"> function toggle(obj) { @@ -151,11 +144,20 @@ function toggle(obj) { } </SCRIPT> +% if ( $msg_template and $msg_template->disabled ) { +% # if we've already established a draft template, don't let msgnum be changed + <& /elements/hidden.html, + field => 'msgnum', + curr_value => ($cgi->param('msgnum') || ''), + &> +% } else { Template: <& /elements/select-msg_template.html, - onchange => 'toggle(this)', + onchange => 'toggle(this)', + curr_value => ($cgi->param('msgnum') || ''), &> <BR> +% } <TABLE BGCOLOR="#cccccc" CELLSPACING=0 WIDTH="100%" id="table_no_template"> <& /elements/tr-td-label.html, 'label' => 'From:' &> <TD><& /elements/input-text.html, @@ -163,46 +165,41 @@ Template: 'value' => $conf->config('invoice_from_name', $agent_virt_agentnum) || $conf->config('company_name', $agent_virt_agentnum), #? 'size' => 20, + 'curr_value' => $cgi->param('from_name'), &> <\ <& /elements/input-text.html, 'field' => 'from_addr', 'type' => 'email', # HTML5, woot 'value' => $conf->config('invoice_from', $agent_virt_agentnum), 'size' => 20, + 'curr_value' => $cgi->param('from_addr'), &>></TD> <& /elements/tr-input-text.html, 'field' => 'subject', 'label' => 'Subject:', 'size' => 50, + 'curr_value' => $subject, &> <TR> <TD ALIGN="right" VALIGN="top" STYLE="padding-top:3px">Message: </TD> <TD><& /elements/htmlarea.html, - 'field' => 'html_body', + 'field' => 'body', 'width' => 763, + 'curr_value' => $body, &> </TD> </TR> </TABLE> -%#Substitution vars: - - <INPUT TYPE="hidden" NAME="action" VALUE="preview"> - <INPUT TYPE="submit" VALUE="Preview notice"> + <INPUT TYPE="submit" NAME="preview" VALUE="Preview notice"> % } #end not action or alternate form </FORM> -% if ( $cgi->param('action') eq 'send' ) { - <SCRIPT TYPE="text/javascript"> - process(); - </SCRIPT> -% } - <& /elements/footer.html &> <%init> @@ -215,7 +212,7 @@ 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 @no_search_fields = qw( table from subject html_body text_body popup url ); my $form_action = $opt{'form_action'} || 'email-customers.html'; my $process_url = $opt{'process_url'} || 'process/email-customers.html'; @@ -259,12 +256,26 @@ if ( $cgi->param('from') ) { $from = $cgi->param('from_addr'); } -my $subject = $cgi->param('subject') || ''; -my $html_body = $cgi->param('html_body') || ''; - my $msg_template = ''; +if ( $cgi->param('msgnum') =~ /^(\d+)$/ ) { + $msg_template = FS::msg_template->by_key($1) + or die "template not found: ".$cgi->param('msgnum'); +} -if ( $cgi->param('action') eq 'preview' ) { +my $subject = $cgi->param('subject'); +my $body = $cgi->param('body'); +my ($html_body, $text_body); + +if ( !$cgi->param('preview') ) { + + # edit mode: initialize the fields from the saved draft, if there is one + if ( $msg_template and $msg_template->disabled eq 'D' ) { + my $content = $msg_template->content(''); # no localization on these yet + $subject ||= $content->subject; + $body ||= $content->body; + } + +} else { my $sql_query = "FS::$table"->search(\%search); my $count_query = delete($sql_query->{'count_query'}); @@ -275,10 +286,40 @@ if ( $cgi->param('action') eq 'preview' ) { my $count_arrayref = $count_sth->fetchrow_arrayref; $num_cust = $count_arrayref->[0]; - if ( $cgi->param('msgnum') ) { - $msg_template = qsearchs('msg_template', - { msgnum => scalar($cgi->param('msgnum')) } ) - or die "template not found: ".$cgi->param('msgnum'); + if ( !$msg_template or $msg_template->disabled eq 'D' ) { + # then this is a one-off template; edit it in place + my $subject = $cgi->param('subject') || ''; + my $body = $cgi->param('body') || ''; + + # create a draft template + $msg_template ||= FS::msg_template->new({ + msgclass => 'email', + disabled => 'D', + }); + # anyone have a better idea for msgname? + $msg_template->set('msgname' => "Notice " . DateTime->now->iso8601); + $msg_template->set('from_addr' => $from); + my %content = ( + subject => $subject, + body => $body, + ); + my $error; + if ( $msg_template->msgnum ) { + $error = $msg_template->replace(%content); + } else { + $error = $msg_template->insert(%content); + } + + if ( $error ) { + $cgi->param('error', $error); + $cgi->delete('preview'); # don't go on to preview stage yet + undef $msg_template; + } + } + # unless creating the msg_template failed, we now have one, so construct a + # preview message from the first customer/whatever in the search results + + if ( $msg_template ) { $sql_query->{'extra_sql'} .= ' LIMIT 1'; $sql_query->{'select'} = "$table.*"; $sql_query->{'order_by'} = ''; @@ -288,8 +329,13 @@ if ( $cgi->param('action') eq 'preview' ) { 'cust_main' => $cust, 'object' => $object, ); - my %message = $msg_template->prepare(%msgopts); - ($from, $subject, $html_body) = @message{'from', 'subject', 'html_body'}; + + my $cust_msg = $msg_template->prepare(%msgopts); + $from = $cust_msg->env_from; + $html_body = $cust_msg->preview; + if ( $cust_msg->header =~ /^subject: (.*)/mi ) { + $subject = $1; + } } } diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 799165fe0..cb2bd4832 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -5,11 +5,6 @@ } &> -<& /elements/xmlhttp.html, - 'url' => $p.'misc/xmlhttp-part_pkg_usageprice.html', - 'subs' => [ 'get_part_pkg_usageprice' ], -&> - <& /elements/init_calendar.html &> <SCRIPT TYPE="text/javascript" SRC="../elements/order_pkg.js"></SCRIPT> @@ -121,19 +116,9 @@ </TABLE><BR> -%#so: -%# - hide until you selecdt a pacakge with add-ons -%# -lookup and display the available add-ons when -%# -add them to the (recur if there is one, otherwise setup) price and display magically like processing fees do on edit/cust_pay.cgi - -%# better label? -<FONT CLASS = "fsinnerbox-title" - ID = "cust_pkg_usageprice_title" - STYLE = "display:none" -><% mt('Usage add-ons') |h %></FONT> -<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 ID="cust_pkg_usageprice_table"> - -</TABLE> +<% include('/misc/cust_pkg_usageprice.html', + 'pkgpart' => $pkgpart + ) %> <BR> % my $discount_cust_pkg = $curuser->access_right('Discount customer package'); diff --git a/httemplate/misc/process/deploy_zone-block_lookup.cgi b/httemplate/misc/process/deploy_zone-block_lookup.cgi new file mode 100644 index 000000000..8f4eac7e9 --- /dev/null +++ b/httemplate/misc/process/deploy_zone-block_lookup.cgi @@ -0,0 +1,13 @@ +<% $server->process %> +<%init> +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" + unless $curuser->access_right([ + 'Edit FCC report configuration', + 'Edit FCC report configuration for all agents', + ]); + +my $server = FS::UI::Web::JSRPC->new( + 'FS::deploy_zone::process_block_lookup', $cgi +); +</%init> diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index 27b818660..efba9ed9a 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -74,11 +74,13 @@ $cgi->param('balance') =~ /^\s*(\-?\s*\d*(\.\d\d)?)\s*$/ my $balance = $1; my $payinfo; +my $paymask; # override only used by loaded cust payinfo, only implemented for realtime processing my $paycvv = ''; if ( $payby eq 'CHEK' ) { if ($cgi->param('payinfo1') =~ /xx/i || $cgi->param('payinfo2') =~ /xx/i ) { $payinfo = $cust_main->payinfo; + $paymask = $cust_main->paymask; } else { $cgi->param('payinfo1') =~ /^(\d+)$/ or errorpage("Illegal account number ". $cgi->param('payinfo1')); @@ -99,6 +101,7 @@ if ( $payby eq 'CHEK' ) { $payinfo = $cgi->param('payinfo'); if ($payinfo eq $cust_main->paymask) { $payinfo = $cust_main->payinfo; + $paymask = $cust_main->paymask; } $payinfo =~ s/\D//g; $payinfo =~ /^(\d{13,16}|\d{8,9})$/ @@ -135,6 +138,46 @@ $cgi->param('discount_term') =~ /^(\d*)$/ or errorpage("illegal discount_term"); my $discount_term = $1; +# save first, for proper tokenization later +if ( $cgi->param('save') ) { + my $new = new FS::cust_main { $cust_main->hash }; + if ( $payby eq 'CARD' ) { + $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) ); + } elsif ( $payby eq 'CHEK' ) { + $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) ); + } else { + die "unknown payby $payby"; + } + $new->payinfo($payinfo); # sets default paymask, but not if it's already tokenized + $new->paymask($paymask) if $paymask; # in case it's been tokenized, override with loaded paymask + $new->set( 'paydate' => "$year-$month-01" ); + $new->set( 'payname' => $payname ); + + #false laziness w/FS:;cust_main::realtime_bop - check both to make sure + # working correctly + if ( $payby eq 'CARD' && + grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) { + $new->set( 'paycvv' => $paycvv ); + } else { + $new->set( 'paycvv' => ''); + } + + if ( $payby eq 'CARD' ) { + my $bill_location = FS::cust_location->new; + $bill_location->set( $_ => $cgi->param($_) ) + foreach @{$payby2fields{$payby}}; + $new->set('bill_location' => $bill_location); + # will do nothing if the fields are all unchanged + } else { + $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}}; + } + + my $error = $new->replace($cust_main); + errorpage("error saving info, payment not processed: $error") + if $error; + $cust_main = $new; +} + my $error = ''; my $paynum = ''; if ( $cgi->param('batch') ) { @@ -160,6 +203,7 @@ if ( $cgi->param('batch') ) { 'manual' => 1, 'balance' => $balance, 'payinfo' => $payinfo, + 'paymask' => $paymask, 'paydate' => "$year-$month-01", 'payname' => $payname, 'payunique' => $payunique, @@ -190,44 +234,6 @@ if ( $cgi->param('batch') ) { } -if ( $cgi->param('save') ) { - my $new = new FS::cust_main { $cust_main->hash }; - if ( $payby eq 'CARD' ) { - $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) ); - } elsif ( $payby eq 'CHEK' ) { - $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) ); - } else { - die "unknown payby $payby"; - } - $new->set( 'payinfo' => $cust_main->card_token || $payinfo ); - $new->set( 'paydate' => "$year-$month-01" ); - $new->set( 'payname' => $payname ); - - #false laziness w/FS:;cust_main::realtime_bop - check both to make sure - # working correctly - if ( $payby eq 'CARD' && - grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) { - $new->set( 'paycvv' => $paycvv ); - } else { - $new->set( 'paycvv' => ''); - } - - if ( $payby eq 'CARD' ) { - my $bill_location = FS::cust_location->new; - $bill_location->set( $_ => $cgi->param($_) ) - foreach @{$payby2fields{$payby}}; - $new->set('bill_location' => $bill_location); - # will do nothing if the fields are all unchanged - } else { - $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}}; - } - - my $error = $new->replace($cust_main); - errorpage("payment processed successfully, but error saving info: $error") - if $error; - $cust_main = $new; -} - #success! </%init> diff --git a/httemplate/misc/process/send-report.html b/httemplate/misc/process/send-report.html new file mode 100644 index 000000000..3bceebc0c --- /dev/null +++ b/httemplate/misc/process/send-report.html @@ -0,0 +1,7 @@ +<%init> +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers'); + +my $server = FS::UI::Web::JSRPC->new('FS::report_batch::process_send_report', $cgi); +</%init> +<% $server->process %> diff --git a/httemplate/misc/process/template_image-delete.cgi b/httemplate/misc/process/template_image-delete.cgi new file mode 100644 index 000000000..58c3f2c68 --- /dev/null +++ b/httemplate/misc/process/template_image-delete.cgi @@ -0,0 +1,28 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +# make sure user can generally edit +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +# make sure user can edit this particular image +my %arg = $cgi->param('arg'); +my $imgnum = $arg{'imgnum'}; +die "bad imgnum" unless $imgnum =~ /^\d+$/; +die "access denied" unless qsearchs({ + 'table' => 'template_image', + 'select' => 'imgnum', + 'hashref' => { 'imgnum' => $imgnum }, + 'extra_sql' => ' AND ' . + $curuser->agentnums_sql( + 'null_right' => ['Edit global templates'] + ), + }); + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_delete', $cgi; + +</%init> diff --git a/httemplate/misc/process/template_image-upload.cgi b/httemplate/misc/process/template_image-upload.cgi new file mode 100644 index 000000000..c3c905981 --- /dev/null +++ b/httemplate/misc/process/template_image-upload.cgi @@ -0,0 +1,26 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +my %arg = $cgi->param('arg'); +my $agentnum = $arg{'agentnum'}; + +if (!$agentnum) { + die "access denied" + unless $curuser->access_right([ 'Edit global templates' ]); +} else { + die "bad agentnum" + unless $agentnum =~ /^\d+$/; + die "access denied" + unless $curuser->agentnum($agentnum); +} + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_upload', $cgi; + +</%init> diff --git a/httemplate/misc/process/void-cust_bill.html b/httemplate/misc/process/void-cust_bill.html index accee27fd..7773b0ba9 100755 --- a/httemplate/misc/process/void-cust_bill.html +++ b/httemplate/misc/process/void-cust_bill.html @@ -21,6 +21,6 @@ my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum}); my $custnum = $cust_bill->custnum; -my $error = $cust_bill->void( $cgi->param('reason') ); +my $error = $cust_bill->void( scalar($cgi->param('reason')) ); </%init> diff --git a/httemplate/misc/send-report.html b/httemplate/misc/send-report.html new file mode 100644 index 000000000..557767a57 --- /dev/null +++ b/httemplate/misc/send-report.html @@ -0,0 +1,166 @@ +<%doc> + +Parameters: + +- reportname: the report name (per FS::report_batch) + +</%doc> +<& /elements/header-popup.html, { title => $report_info->{name} } &> +<script type="text/javascript"> + +$().ready(function() { + var agent_info = <% encode_json(\%agent) %>; + + $('#agentnum').on('change', function() { + var agentnum = this.value; + if ( agent_info[agentnum] ) { + $('#msgnum').prop('value', agent_info[agentnum]['msgnum']); + $('#beginning_text').prop('value', agent_info[agentnum]['beginning']); + $('#ending_text').prop('value', agent_info[agentnum]['ending']); + } else { + $('#msgnum').prop('value', ''); + $('#beginning_text').prop('value', ''); + $('#ending_text').prop('value', ''); + } + }); + + $('#agentnum').trigger('change'); + +}); + +</script> +<FORM NAME="OneTrueForm" ACTION="process/send-report.html" METHOD="POST"> + +<table class="inv"> + <input type="hidden" name="reportname" value="<% $cgi->param('reportname') |h %>"> + + <& /elements/tr-select-agent.html &> + + <& /elements/tr-td-label.html, label => emt('Message template') &> + <TD> + <& /elements/select-msg_template.html, field => 'msgnum' &> + </TD> + </TR> + + <& /elements/tr-input-beginning_ending.html &> + + <& /elements/progress-init.html, + 'OneTrueForm', + [ qw( reportname msgnum agentnum beginning ending ) ], + $p.'misc/process/send-report.html', + { message => 'Reports sent', + url => $cgi->referer } + &> + +</table> + +<INPUT TYPE="button" onclick="process()" VALUE="<% emt('Send reports') %>" /> +</FORM> + +<style> +table.grid { + border-collapse: collapse; + margin-top: 1ex; + margin-left: auto; + margin-right: auto; +} +.grid caption { + font-weight: bold; + margin-bottom: 0.5ex; +} +.grid th,td { + padding-left: 3px; + padding-right: 3px; + padding-bottom: 2px; + border: none; + empty-cells: show; +} +.grid th { + border-bottom: 1px solid #999999; + font-size: 90%; + vertical-align: bottom; +} +</style> + +% if ( @report_history ) { +<hr> +<table class="grid"> +<caption><% emt('Report history') %></caption> +<thead> + <th>Agent</th> + <th>Sent on</th> + <th colspan=2>Date range</th> + <th>User</th> +</thead> +<tbody> +% my $row = 0; +% foreach my $report (@report_history) { +% my $agent = ($report->agentnum ? +% $report->agent->agent : 'All agents'); + <tr class="row<% $row % 2 %>"> + <td><% $agent %></td> + <td><% time2str($date_format, $report->send_date) %></td> + <td><% time2str($date_format, $report->sdate) %></td> + <td><% time2str($date_format, $report->edate) %></td> + <td><% $report->access_user->username %></td> + </tr> +% $row++; +% } +</tbody> +</table> +% } + +<& /elements/footer.html &> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers'); + +$cgi->param('reportname') =~ /^(\w+)$/ + or die "bad reportname"; +my $reportname = $1; +my $report_info = $FS::report_batch::sendable_reports{$reportname} + or die "bad reportname"; + +my $date_format = FS::Conf->new->config('date_format') || '%x'; + +my @report_history = qsearch({ + table => 'report_batch', + hashref => { reportname => $reportname }, + order_by => ' ORDER BY send_date DESC', +}); + +# defaults per agent that could be selected for the report +my %agent; + +foreach my $report ( @report_history ) { + my $agentnum = $report->agentnum; + next if $agent{$agentnum}; + + # estimate the width of the report period, in months + my $last_sdate = DateTime->from_epoch( epoch => $report->sdate ); + my $last_edate = DateTime->from_epoch( epoch => $report->edate ); + + my $days = $last_sdate->delta_days( $last_edate )->delta_days; + my $months = sprintf('%.0f', $days / 6) / 5; + + my $next_sdate = $last_edate->clone->add(days => 1); + my $next_edate = $next_sdate->clone; + if ( $months >= 1 ) { # then treat as an interval in months + $next_edate->add( months => sprintf('%.0f', $months) ); + $next_edate->subtract(days => 1); + } else { # treat as a number of days + $next_edate->add( days => $days ); + } + + my $name = $agentnum ? FS::agent->by_key($agentnum)->agent : 'All agents'; + $agent{$agentnum} = { + name => $name, + beginning => $next_sdate->strftime($date_format), + ending => $next_edate->strftime($date_format), + msgnum => $report->msgnum, + }; +} + +</%init> diff --git a/httemplate/misc/unapply-cust_pay.cgi b/httemplate/misc/unapply-cust_pay.cgi index 8cdac180b..b0343d034 100755 --- a/httemplate/misc/unapply-cust_pay.cgi +++ b/httemplate/misc/unapply-cust_pay.cgi @@ -12,9 +12,7 @@ my $paynum = $1; my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); my $custnum = $cust_pay->custnum; -foreach my $cust_bill_pay ( $cust_pay->cust_bill_pay ) { - my $error = $cust_bill_pay->delete; - errorpage($error) if $error; -} +my $error = $cust_pay->delete_cust_bill_pay; +errorpage($error) if $error; </%init> diff --git a/httemplate/misc/void-cust_bill.html b/httemplate/misc/void-cust_bill.html index 1608fd051..39b071229 100644 --- a/httemplate/misc/void-cust_bill.html +++ b/httemplate/misc/void-cust_bill.html @@ -14,7 +14,7 @@ <% ntable("#cccccc", 2) %> <TR> <TD ALIGN="right">Reason</TD> - <TD><INPUT TYPE="text" NAME="reason" VALUE="<% $cgi->param('reason') |h %>"></TD> + <TD><INPUT TYPE="text" NAME="reason" VALUE="<% scalar($cgi->param('reason')) |h %>"></TD> </TR> </TABLE> diff --git a/httemplate/misc/xmlhttp-part_pkg_usageprice.html b/httemplate/misc/xmlhttp-part_pkg_usageprice.html index d4e2d8469..9decdeff9 100644 --- a/httemplate/misc/xmlhttp-part_pkg_usageprice.html +++ b/httemplate/misc/xmlhttp-part_pkg_usageprice.html @@ -1,24 +1,32 @@ <% encode_json( \@return ) %>\ <%init> -my( $pkgpart ) = $cgi->param('arg'); +my( $pkgpart, $pkgnum ) = $cgi->param('arg'); #could worry about agent-virting this so you can't see the add-on pricing of # other agents, but not a real-world big worry my $part_pkg = qsearchs( 'part_pkg', { pkgpart=>$pkgpart } ); +my %curr_quantity; +if ($pkgnum) { + my $cust_pkg = qsearchs( 'cust_pkg', { pkgnum=>$pkgnum } ); + %curr_quantity = map { $_->usagepricepart, $_->quantity } $cust_pkg->cust_pkg_usageprice; +} + my $num = 0; -my @return = map { +# probably don't need to be returning js_only anymore? +my @return = ($pkgpart, map { + my $usagepricepart = $_->usagepricepart; my @inc = ('/elements/cust_pkg_usageprice.html', - 'usagepricepart' => $_->usagepricepart, + 'usagepricepart' => $usagepricepart, ); - + push(@inc,'curr_quantity',($curr_quantity{$usagepricepart} || 0)); ( include(@inc, field=>'usagepricenum'.$num, html_only=>1 ), include(@inc, field=>'usagepricenum'.$num++, js_only=>1 ), ); } - $part_pkg->part_pkg_usageprice; + $part_pkg->part_pkg_usageprice); </%init> diff --git a/httemplate/misc/xmlhttp-template_image.cgi b/httemplate/misc/xmlhttp-template_image.cgi new file mode 100644 index 000000000..a8c50edf0 --- /dev/null +++ b/httemplate/misc/xmlhttp-template_image.cgi @@ -0,0 +1,48 @@ +<%doc> +Returns JSON encoded array of objects with details about FS::template_image +objects. Attributes in each returned object are imgnum, name, and src. + +Accepts the following options: + +imgnum - only return object for this imgnum + +no_src - do not include the src field + +</%doc> +<% encode_json(\@result) %>\ +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my %arg = $cgi->param('arg'); + +my $search = { + 'table' => 'template_image', + 'hashref' => {}, +}; + +my $imgnum = $arg{'imgnum'} || ''; +die "Bad imgnum" unless $imgnum =~ /^\d*$/; +$search->{'hashref'}->{'imgnum'} = $imgnum if $imgnum; + +$search->{'select'} = 'imgnum, name' if $arg{'no_src'}; + +$search->{'extra_sql'} = ($imgnum ? ' AND ' : ' WHERE ') + . $curuser->agentnums_sql( + 'null_right' => ['View global templates','Edit global templates'] + ); + +my @images = qsearch($search); #needs agent virtualization + +my @result = map { +{ + 'imgnum' => $_->imgnum, + 'name' => $_->name, + 'src' => $arg{'no_src'} ? '' : $_->src, +} } @images; + +</%init> diff --git a/httemplate/misc/xmlhttp-ticket-update.html b/httemplate/misc/xmlhttp-ticket-update.html new file mode 100644 index 000000000..147fbef16 --- /dev/null +++ b/httemplate/misc/xmlhttp-ticket-update.html @@ -0,0 +1,66 @@ +<% encode_json($return) %>\ +<%init> + +my $id = $cgi->param('id'); +my $starts = $cgi->param('starts'); +my $due = $cgi->param('due'); +my $username = $cgi->param('username'); + +my $ticket = FS::TicketSystem->get_ticket_object( \%session, ticket_id=>$id ); + +#hmm, this should happen in a single transaction and either commit or rollback, +# but in reality failures "Don't Happen" so its not like a ticket gets +# half changed + +my $return; +if ( $ticket ) { + + my($orv, $omsg) = $ticket->SetOwner( $username, 'Steal' ); + $orv = 1 if ! $orv && $omsg =~ /already owns/i; + + if ( $orv ) { + + my $date = RT::Date->new( $session{CurrentUser} ); + $date->Set( Format=>'unix', Value=>$starts, ); + my($srv, $smsg) = $ticket->SetStarts( $date->ISO ); + + my $ddate; + unless ( ! $srv ) { + $ddate = RT::Date->new( $session{CurrentUser} ); + $ddate->Set( Format=>'unix', Value=>$due, ); + my($drv, $dmsg) = $ticket->SetDue( $ddate->ISO ); + #XXX lame + } + + if ( $srv ) { + + my ($sm, $sh) = ( $date->Localtime('user'))[1,2]; + my ($em, $eh) = ($ddate->Localtime('user'))[1,2]; + + #false laziness w/CalendarSlotSchedule and CalendarDaySchedule + my %hash = $m->comp('/rt/Ticket/Elements/Customers', Ticket => $ticket); + my @cust_main = values( %{$hash{cust_main}} ); + + $return = { 'error' => '', + #'starts' => $starts, + #'due' => $due, + #'username' => $username, + #false laziness w/CalendarSlotSchedule + 'sched_label' => + FS::sched_avail::pretty_time($sh*60+$sm). '-'. + FS::sched_avail::pretty_time($eh*60+$em). ': '. + $cust_main[0]->_FreesideURILabel, + }; + } else { + $return = { 'error' => $smsg }; + } + + } else { + $return = { 'error' => $omsg }; + } + +} else { + $return = { 'error' => 'Unknown ticket id' }; +} + +</%init> |