summaryrefslogtreecommitdiff
path: root/httemplate/edit
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/edit')
-rwxr-xr-xhttemplate/edit/agent_type.cgi2
-rw-r--r--httemplate/edit/cdr_type.cgi22
-rw-r--r--httemplate/edit/credit-cust_bill_pkg.html249
-rwxr-xr-xhttemplate/edit/cust_credit.cgi1
-rw-r--r--httemplate/edit/elements/part_export/broadband_snmp.html101
-rw-r--r--httemplate/edit/elements/part_export/foot.html6
-rw-r--r--httemplate/edit/elements/part_export/head.html19
-rw-r--r--httemplate/edit/part_export.cgi9
-rwxr-xr-xhttemplate/edit/part_pkg.cgi24
-rw-r--r--httemplate/edit/process/cdr_type.cgi1
-rw-r--r--httemplate/edit/process/credit-cust_bill_pkg.html44
-rwxr-xr-xhttemplate/edit/process/cust_credit.cgi4
-rw-r--r--httemplate/edit/process/part_export.cgi29
-rw-r--r--httemplate/edit/rate_time.cgi41
14 files changed, 522 insertions, 30 deletions
diff --git a/httemplate/edit/agent_type.cgi b/httemplate/edit/agent_type.cgi
index 8a6fbc255..b75757fb1 100755
--- a/httemplate/edit/agent_type.cgi
+++ b/httemplate/edit/agent_type.cgi
@@ -20,7 +20,7 @@ Select which packages agents of this type may sell to customers<BR>
'source_obj' => $agent_type,
'link_table' => 'type_pkgs',
'target_table' => 'part_pkg',
- 'name_callback' => sub { $_[0]->pkg_comment(nopkgpart => 1); },
+ 'name_callback' => sub { encode_entities( $_[0]->pkg_comment(nopkgpart => 1) ); },
'target_link' => $p.'edit/part_pkg.cgi?',
'disable-able' => 1,
diff --git a/httemplate/edit/cdr_type.cgi b/httemplate/edit/cdr_type.cgi
index 5d2c66216..c69610607 100644
--- a/httemplate/edit/cdr_type.cgi
+++ b/httemplate/edit/cdr_type.cgi
@@ -7,11 +7,24 @@ calls and SMS messages. Each CDR type must have a set of rates
configured in the rate tables.
<BR>
<FORM METHOD="POST" ACTION="<% "${p}edit/process/cdr_type.cgi" %>">
-<% include('/elements/auto-table.html',
- 'header' => [ 'Type#', 'Name' ],
- 'fields' => [ qw( cdrtypenum cdrtypename ) ],
+<TABLE ID="AutoTable" BORDER=0 CELLSPACING=0>
+ <TR>
+ <TH>Type#</TH>
+ <TH>Name</TH>
+ </TR>
+ <TR ID="cdr_template">
+ <TD>
+ <INPUT NAME="cdrtypenum" SIZE=16 MAXLENGTH=16 ALIGN="right">
+ </TD>
+ <TD>
+ <INPUT NAME="cdrtypename" SIZE=16 MAXLENGTH=16>
+ </TD>
+ </TR>
+<& /elements/auto-table.html,
+ 'template_row' => 'cdr_template',
'data' => \@data,
- ) %>
+&>
+</TABLE>
<INPUT TYPE="submit" VALUE="Apply changes"> </FORM> <BR>
<% include('/elements/footer.html') %>
<%init>
@@ -20,7 +33,6 @@ die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
my @data = (
- map { [ $_->cdrtypenum, $_->cdrtypename ] }
qsearch({
'table' => 'cdr_type',
'hashref' => {},
diff --git a/httemplate/edit/credit-cust_bill_pkg.html b/httemplate/edit/credit-cust_bill_pkg.html
new file mode 100644
index 000000000..e317936b3
--- /dev/null
+++ b/httemplate/edit/credit-cust_bill_pkg.html
@@ -0,0 +1,249 @@
+<& /elements/header-popup.html, 'Credit line items' &>
+
+<FORM ACTION="process/credit-cust_bill_pkg.html" METHOD="POST">
+<INPUT TYPE="hidden" NAME="crednum" VALUE="">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum |h %>">
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="">
+<INPUT TYPE="hidden" NAME="_date" VALUE="<% time %>">
+<table>
+
+% my $old_invnum = 0;
+%# foreach my $cust_bill_pkg ( @cust_bill_pkg ) {
+% foreach my $item ( @items ) {
+% my( $setuprecur, $cust_bill_pkg ) = @$item;
+
+% my $method = $setuprecur eq 'setup' ? 'setup' : 'recur';
+% my $amount = $cust_bill_pkg->$method();
+% my $credited = $cust_bill_pkg->credited('', '', 'setuprecur'=>$method);
+% $amount -= $credited;
+% $amount = sprintf('%.2f', $amount);
+% next unless $amount > 0;
+
+% if ( $cust_bill_pkg->invnum ne $old_invnum ) {
+ <TR><TD COLSPAN=3 BGCOLOR="#f8f8f8">&nbsp;</TD></TR>
+ <TR><TH COLSPAN=3 BGCOLOR="#f8f8f8" ALIGN="left">Invoice #<% $cust_bill_pkg->invnum %> - <% time2str($date_format, $cust_bill_pkg->cust_bill->_date) %></TD></TR>
+% $old_invnum = $cust_bill_pkg->invnum;
+% }
+
+ <TR>
+ <TD>
+ <INPUT TYPE = "checkbox"
+ NAME = "billpkgnum<% $cust_bill_pkg->billpkgnum.'-'. $setuprecur %>"
+ VALUE = "<% $amount %>"
+ onClick = "calc_total(this)"
+ data-amount = "<% $amount %>"
+ data-billpkgnum = "<% $cust_bill_pkg->billpkgnum %>"
+ data-setuprecur = "<% $setuprecur %>"
+ >
+ </TD>
+ <TD BGCOLOR="#ffffff"><% $cust_bill_pkg->desc |h %></TD>
+%# show one-time/setup vs recur vs usage?
+ <TD BGCOLOR="#ffffff" ALIGN="right"><% $money_char. $amount %></TD>
+ </TR>
+
+% }
+
+<TR><TD COLSPAN=3 BGCOLOR="#f8f8f8">&nbsp;</TD></TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="right">Subtotal: </TD>
+ <TD ALIGN="right" ID="subtotal_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="right">Taxes: </TD>
+ <TD ALIGN="right" ID="taxtotal_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TH ALIGN="right">Total credit amount: </TD>
+ <TH ALIGN="right" ID="total_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
+</TR>
+<INPUT TYPE="hidden" NAME="amount" ID="total_el" VALUE="0.00">
+
+</table>
+
+<table>
+
+<& /elements/tr-select-reason.html,
+ 'field' => 'reasonnum',
+ 'reason_class' => 'R',
+ #XXX reconcile both this and show_taxes wanteding to enable this
+ 'control_button' => "document.getElementById('credit_button')",
+ 'cgi' => $cgi,
+&>
+
+<TR>
+ <TD ALIGN="right"><% mt('Additional info') |h %></TD>
+ <TD>
+ <INPUT TYPE="text" NAME="addlinfo" VALUE="<% $cgi->param('addlinfo') |h %>">
+ </TD>
+</TR>
+
+</table>
+
+<BR>
+<INPUT TYPE="submit" ID="credit_button" VALUE="Credit" DISABLED>
+
+</FORM>
+
+<% include( '/elements/xmlhttp.html',
+ 'url' => $p.'misc/xmlhttp-cust_bill_pkg-calculate_taxes.html',
+ 'subs' => [ 'calculate_taxes' ],
+ )
+%>
+<SCRIPT TYPE="text/javascript">
+
+function show_taxes(arg) {
+ var argsHash = eval('(' + arg + ')');
+
+ //XXX add an 'ErrorMessage' section to the HTML and re-enable
+ //var error = argsHash['error'];
+
+ //var paragraph = document.getElementById('ErrorMessage');
+ //if (error) {
+ // paragraph.innerHTML = 'Error: ' + error;
+ // paragraph.style.color = '#ff0000';
+ //} else {
+ // paragraph.innerHTML = '';
+ //}
+
+ var taxlines = argsHash['taxlines'];
+
+//XXX display the tax lines? just a total will do for now
+//
+// var table = document.getElementById('ApplicationTable');
+//
+// var aFoundRow = 0;
+// for (i = 0; taxlines[i]; i++) {
+// var itemdesc = taxlines[i][0];
+// var locnum = taxlines[i][2];
+// if (taxlines[i][3]) {
+// locnum = taxlines[i][3];
+// }
+//
+// var found = 0;
+// for (var row = 2; table.rows[row]; row++) {
+// var inputs = table.rows[row].getElementsByTagName('input');
+// if (! inputs.length) {
+// while ( table.rows[row] ) {
+// table.deleteRow(row);
+// }
+// break;
+// }
+// if ( inputs.item(4).value == itemdesc && inputs.item(2).value == locnum )
+// {
+// inputs.item(0).value = taxlines[i][1];
+// aFoundRow = found = row;
+// break;
+// }
+// }
+// if (! found) {
+// var row = table.insertRow(table.rows.length);
+// var warning_cell = document.createElement('TD');
+// warning_cell.style.color = '#ff0000';
+// warning_cell.colSpan = 2;
+// warning_cell.innerHTML = 'Calculated Tax - ' + itemdesc + ' - ' +
+// taxlines[i][1] + ' will not be applied';
+// row.appendChild(warning_cell);
+// }
+// }
+//
+// if (aFoundRow) {
+// sub_changed(table.rows[aFoundRow].getElementsByTagName('input').item(0));
+// }
+
+ var subtotal = parseFloat( argsHash['subtotal'] );
+
+ var taxtotal = parseFloat( argsHash['taxtotal'] );
+ document.getElementById('taxtotal_td').innerHTML =
+ '<% $money_char %>' + taxtotal.toFixed(2);
+
+ var total = subtotal + taxtotal;
+ document.getElementById('total_td').innerHTML =
+ '<% $money_char %>' + total.toFixed(2);
+ document.getElementById('total_el').value = total.toFixed(2);
+
+ //XXX reconcile both this and the reason selector wanteding to enable this
+ if ( total > 0 ) {
+ document.getElementById('credit_button').disabled = false;
+ }
+
+}
+
+function calc_total(what) {
+
+ document.getElementById('credit_button').disabled = true;
+
+ var subtotal = 0;
+ // bah, a pain, just using an attribute var re = /^billpkgnum(\d+)$/;
+
+ var el = what.form.elements;
+ var billpkgnums = [];
+ var setuprecurs = [];
+ var amounts = [];
+ for (var i=0; i<el.length; i++) {
+ if ( el[i].type == 'checkbox' && el[i].checked ) {
+ subtotal += parseFloat( el[i].getAttribute('data-amount') );
+ amounts.push( el[i].getAttribute('data-amount') );
+ billpkgnums.push( el[i].getAttribute('data-billpkgnum') );
+ setuprecurs.push( el[i].getAttribute('data-setuprecur') );
+ }
+ }
+
+ document.getElementById('subtotal_td').innerHTML =
+ '<% $money_char %>' + subtotal.toFixed(2);
+
+ var args = new Array(
+ 'custnum', '<% $custnum %>',
+ 'subtotal', subtotal,
+ 'billpkgnums', billpkgnums.join(),
+ 'setuprecurs', setuprecurs.join(),
+ 'amounts', amounts.join()
+ );
+
+ calculate_taxes( args, show_taxes );
+
+}
+</SCRIPT>
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+die "access denied" unless $curuser->access_right('Post credit');
+
+#a tiny bit of false laziness w/search/cust_bill_pkg.cgi, but we're pretty
+# specialized and a piece of UI, not a report
+#slightly more false laziness w/httemplate/edit/elements/ApplicationCommon.html
+# show_taxes & calc_total here/do_calculate_tax there
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$';
+my $date_format = $conf->config('date_format') || '%m/%d/%Y';
+
+$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum';
+my $custnum = $1;
+
+my $cust_main = qsearchs({
+ 'table' => 'cust_main',
+ 'hashref' => { 'custnum' => $custnum },
+ 'extra_sql' => ' AND '. $curuser->agentnums_sql,
+}) or die 'unknown customer';
+
+my @cust_bill_pkg = qsearch({
+ 'select' => 'cust_bill_pkg.*',
+ 'table' => 'cust_bill_pkg',
+ 'addl_from' => 'LEFT JOIN cust_bill USING (invnum)',
+ 'extra_sql' => "WHERE custnum = $custnum AND pkgnum != 0",
+ 'order_by' => 'ORDER BY invnum ASC, billpkgnum ASC',
+});
+
+my @items = map { my %hash = $_->disintegrate;
+ map [ $_, $hash{$_} ],
+ keys(%hash);
+ }
+ @cust_bill_pkg;
+
+#omit line items which have been previously credited? would be nice
+
+</%init>
diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi
index 6e8a9c989..4dba1e769 100755
--- a/httemplate/edit/cust_credit.cgi
+++ b/httemplate/edit/cust_credit.cgi
@@ -34,6 +34,7 @@
<TD>
<INPUT TYPE="text" NAME="addlinfo" VALUE="<% $cgi->param('addlinfo') |h %>">
</TD>
+ </TR>
% if ( $conf->exists('credits-auto-apply-disable') ) {
<INPUT TYPE="HIDDEN" NAME="apply" VALUE="no">
diff --git a/httemplate/edit/elements/part_export/broadband_snmp.html b/httemplate/edit/elements/part_export/broadband_snmp.html
new file mode 100644
index 000000000..4c0367c5a
--- /dev/null
+++ b/httemplate/edit/elements/part_export/broadband_snmp.html
@@ -0,0 +1,101 @@
+<%doc>
+</%doc>
+<& head.html, %opt &>
+<INPUT TYPE="hidden" NAME="options" VALUE="community,version,ip_addr_change_to_new,timeout">
+<& /elements/tr-select.html,
+ label => 'SNMP version',
+ field => 'version',
+ options => [ '', 'v1', 'v2c' ],
+ labels => { v1 => '1', v2c => '2c' },
+ curr_value => $part_export->option('version') &>
+<& /elements/tr-input-text.html,
+ label => 'Community',
+ field => 'community',
+ curr_value => $part_export->option('community'),
+&>
+<& /elements/tr-checkbox.html,
+ label => 'Send IP address changes to new address',
+ field => 'ip_addr_change_to_new',
+ value => 1,
+ curr_value => $part_export->option('ip_addr_change_to_new'),
+&>
+<& /elements/tr-input-text.html,
+ label => 'Timeout (seconds)',
+ field => 'timeout',
+ curr_value => $part_export->option('timeout'),
+&>
+</TABLE>
+<script type="text/javascript">
+function open_select_mib(obj) {
+ nd(1); // if there's already one open, close it
+ var rownum = obj.rownum;
+ var curr_oid = obj.value || '';
+ var url = '<%$fsurl%>/elements/select-mib-popup.html?' +
+ 'callback=receive_mib;' +
+ 'arg=' + rownum +
+ ';curr_value=' + curr_oid;
+ overlib(
+ OLiframeContent(url, 550, 450, '<% $popup_name %>', 0, 'auto'),
+ CAPTION, 'Select MIB object', STICKY, AUTOSTATUSCAP,
+ MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK,
+ BGCOLOR, '#333399', CGCOLOR, '#333399',
+ CLOSETEXT, 'Close'
+ );
+}
+function receive_mib(obj, rownum) {
+ //console.log(JSON.stringify(obj));
+ // we don't really need the numeric OID or any of the other properties
+ document.getElementById('oid'+rownum).value = obj.fullname;
+ document.getElementById('datatype'+rownum).value = obj.type;
+}
+</script>
+
+<table bgcolor="#cccccc" border=0 cellspacing=3>
+<TR>
+ <TH>Action</TH>
+ <TH>Object</TH>
+ <TH>Type</TH>
+ <TH>Value</TH>
+</TR>
+<TR id="mytemplate">
+ <TD>
+ <SELECT NAME="action">
+% foreach ('', qw(insert delete replace suspend unsuspend)) {
+ <OPTION VALUE="<%$_%>"><%$_%></OPTION>
+% }
+ </SELECT>
+ </TD>
+ <TD>
+ <INPUT NAME="oid" ID="oid" SIZE="60" onclick="open_select_mib(this)">
+ </TD>
+ <TD>
+ <INPUT TYPE="text" NAME="datatype" ID="datatype" READONLY=1>
+ </TD>
+ <TD>
+ <INPUT NAME="value" ID="value">
+ </TD>
+</TR>
+<& /elements/auto-table.html,
+ template_row => 'mytemplate',
+ fieldorder => ['action', 'oid', 'datatype', 'value'],
+ data => \@data,
+&>
+<INPUT TYPE="hidden" NAME="multi_options" VALUE="action,oid,datatype,value">
+<& foot.html, %opt &>
+<%init>
+my %opt = @_;
+my $part_export = $opt{part_export} || FS::part_export->new;
+
+my @actions = split("\n", $part_export->option('action'));
+my @oids = split("\n", $part_export->option('oid'));
+my @types = split("\n", $part_export->option('datatype'));
+my @values = split("\n", $part_export->option('value'));
+
+my @data;
+while (@actions or @oids or @values) {
+ my @thisrow = (shift(@actions), shift(@oids), shift(@types), shift(@values));
+ push @data, \@thisrow if grep length($_), @thisrow;
+}
+
+my $popup_name = 'popup-'.time."-$$-".rand() * 2**32;
+</%init>
diff --git a/httemplate/edit/elements/part_export/foot.html b/httemplate/edit/elements/part_export/foot.html
new file mode 100644
index 000000000..9cb8073ce
--- /dev/null
+++ b/httemplate/edit/elements/part_export/foot.html
@@ -0,0 +1,6 @@
+</TABLE>
+<INPUT TYPE="hidden" NAME="nodomain" VALUE="<% $opt{export_info}{nodomain} %>">
+<INPUT TYPE="submit" VALUE="<% $opt{part_export}->exportnum ? 'Apply changes' : 'Add export' %>">
+<%init>
+my %opt = @_;
+</%init>
diff --git a/httemplate/edit/elements/part_export/head.html b/httemplate/edit/elements/part_export/head.html
new file mode 100644
index 000000000..cb0ab894a
--- /dev/null
+++ b/httemplate/edit/elements/part_export/head.html
@@ -0,0 +1,19 @@
+% if ( $export_info->{no_machine} ) {
+<INPUT TYPE="hidden" NAME="machine" VALUE="">
+<INPUT TYPE="hidden" NAME="svc_machine" VALUE="N">
+% } else {
+% # clone this from edit/part_export.cgi if this case ever gets used
+% }
+<INPUT TYPE="hidden" NAME="exporttype" VALUE="<%$layer |h%>">
+<% ntable('cccccc', 2) %>
+<TR>
+ <TD ALIGN="right" ><% emt('Description') %></TD>
+ <TD BGCOLOR="#ffffff" WIDTH="600"><% $notes %></TD>
+</TR>
+<%init>
+my %opt = @_;
+my $layer = $opt{layer};
+my $part_export = $opt{part_export};
+my $export_info = $opt{export_info};
+my $notes = $opt{notes} || $export_info->{notes};
+</%init>
diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi
index 0407ee77b..4dd253be8 100644
--- a/httemplate/edit/part_export.cgi
+++ b/httemplate/edit/part_export.cgi
@@ -62,6 +62,15 @@ my $widget = new HTML::Widgets::SelectLayers(
'html_between' => "</TD></TR></TABLE>\n",
'layer_callback' => sub {
my $layer = shift;
+ # create 'config_element' to generate the whole layer with a Mason component
+ if ( my $include = $exports->{$layer}{config_element} ) {
+ # might need to adjust the scope of this at some point
+ return $m->scomp($include,
+ part_export => $part_export,
+ layer => $layer,
+ export_info => $exports->{$layer}
+ );
+ }
my $html = qq!<INPUT TYPE="hidden" NAME="exporttype" VALUE="$layer">!.
ntable("#cccccc",2);
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index f3ad8f52d..50aeb4595 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -622,23 +622,23 @@ END
my $warning =
'Changing the setup or recurring fee will create a new package definition. '.
'Continue?';
-
+
+$javascript .= "function confirm_submit(f) {";
if ( $conf->exists('part_pkg-lineage') ) {
$javascript .= "
- function confirm_submit(f) {
-
- var fields = Array('setup_fee','recur_fee');
- for(var i=0; i < fields.length; i++) {
- if ( f[fields[i]].value != f[fields[i]].defaultValue ) {
- return confirm('$warning');
- }
- }
- return true;
+
+ var fields = Array('setup_fee','recur_fee');
+ for(var i=0; i < fields.length; i++) {
+ if ( f[fields[i]].value != f[fields[i]].defaultValue ) {
+ return confirm('$warning');
+ }
}
";
}
-
-$javascript .= '</SCRIPT>';
+$javascript .= "
+ return true;
+}
+</SCRIPT>";
tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() };
diff --git a/httemplate/edit/process/cdr_type.cgi b/httemplate/edit/process/cdr_type.cgi
index b661de75d..ba9881dc4 100644
--- a/httemplate/edit/process/cdr_type.cgi
+++ b/httemplate/edit/process/cdr_type.cgi
@@ -10,7 +10,6 @@ die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
my %vars = $cgi->Vars;
-warn Dumper(\%vars)."\n";
my %old = map { $_->cdrtypenum => $_ } qsearch('cdr_type', {});
diff --git a/httemplate/edit/process/credit-cust_bill_pkg.html b/httemplate/edit/process/credit-cust_bill_pkg.html
new file mode 100644
index 000000000..8b2f3f3ea
--- /dev/null
+++ b/httemplate/edit/process/credit-cust_bill_pkg.html
@@ -0,0 +1,44 @@
+%if ($error) {
+% errorpage_popup($error); #XXX redirect back for correction...
+%} else {
+<& /elements/header-popup.html, 'Credit successful' &>
+ <SCRIPT TYPE="text/javascript">
+ window.top.location.reload();
+ </SCRIPT>
+ </BODY></HTML>
+% }
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Post credit');
+
+my @billpkgnum_setuprecurs =
+ map { $_ =~ /^billpkgnum(\d+\-\w*)$/ or die 'gm#23'; $1; }
+ grep { $_ =~ /^billpkgnum\d+\-\w*$/ && $cgi->param($_) } $cgi->param;
+
+my @billpkgnums = ();
+my @setuprecurs = ();
+my @amounts = ();
+foreach my $billpkgnum_setuprecur (@billpkgnum_setuprecurs) {
+ my $amount = $cgi->param("billpkgnum$billpkgnum_setuprecur");
+ my( $billpkgnum, $setuprecur ) = split('-', $billpkgnum_setuprecur);
+ push @billpkgnums, $billpkgnum;
+ push @setuprecurs, $setuprecur;
+ push @amounts, $amount;
+}
+
+my $error = FS::cust_credit->credit_lineitems(
+ #the lineitems to credit
+ 'billpkgnums' => \@billpkgnums,
+ 'setuprecurs' => \@setuprecurs,
+ 'amounts' => \@amounts,
+
+ #the credit
+ 'newreasonnum' => scalar($cgi->param('newreasonnum')),
+ 'newreasonnum_type' => scalar($cgi->param('newreasonnumT')),
+ map { $_ => scalar($cgi->param($_)) }
+ #fields('cust_credit')
+ qw( custnum _date amount reason reasonnum addlinfo ), #pkgnum eventnum
+);
+
+</%init>
diff --git a/httemplate/edit/process/cust_credit.cgi b/httemplate/edit/process/cust_credit.cgi
index 776112ac0..245f31af7 100755
--- a/httemplate/edit/process/cust_credit.cgi
+++ b/httemplate/edit/process/cust_credit.cgi
@@ -15,7 +15,7 @@
%
% $dbh->commit or die $dbh->errstr if $oldAutoCommit;
%
-<% header(emt('Credit sucessful')) %>
+<% header(emt('Credit successful')) %>
<SCRIPT TYPE="text/javascript">
window.top.location.reload();
</SCRIPT>
@@ -27,7 +27,7 @@
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Post credit');
-$cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!";
+$cgi->param('custnum') =~ /^(\d+)$/ or die "Illegal custnum!";
my $custnum = $1;
$cgi->param('reasonnum') =~ /^(-?\d+)$/ or die "Illegal reasonnum";
diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi
index 6432d6b15..bcb9c0df1 100644
--- a/httemplate/edit/process/part_export.cgi
+++ b/httemplate/edit/process/part_export.cgi
@@ -13,15 +13,40 @@ my $exportnum = $cgi->param('exportnum');
my $old = qsearchs('part_export', { 'exportnum'=>$exportnum } ) if $exportnum;
+my %vars = $cgi->Vars;
#fixup options
#warn join('-', split(',',$cgi->param('options')));
my %options = map {
- my @values = $cgi->param($_);
- my $value = scalar(@values) > 1 ? join (' ', @values) : $values[0];
+ my $value = $vars{$_};
+ $value =~ s/\0/ /g; # deal with multivalued options
$value =~ s/\r\n/\n/g; #browsers? (textarea)
$_ => $value;
} split(',', $cgi->param('options'));
+# deal with multiline options
+# %vars should never contain incomplete rows, but just in case it does,
+# we make a list of all the row indices that contain values, and
+# then write a line in each option for each row, even if it's empty.
+# This ensures that all values with the same row index line up.
+my %optionrows;
+foreach my $option (split(',', $cgi->param('multi_options'))) {
+ $optionrows{$option} = {};
+ my %values; # bear with me
+ for (keys %vars) {
+ /^$option(\d+)/ or next;
+ $optionrows{$option}{$1} = $vars{$option.$1};
+ $optionrows{_ALL_}{$1} = 1 if length($vars{$option.$1});
+ }
+}
+foreach my $option (split(',', $cgi->param('multi_options'))) {
+ my $value = '';
+ foreach my $row (sort keys %{$optionrows{_ALL_}}) {
+ $value .= ($optionrows{$option}{$row} || '') . "\n";
+ }
+ chomp($value);
+ $options{$option} = $value;
+}
+
my $new = new FS::part_export ( {
map {
$_, scalar($cgi->param($_));
diff --git a/httemplate/edit/rate_time.cgi b/httemplate/edit/rate_time.cgi
index 7ee39efca..9e6b8736c 100644
--- a/httemplate/edit/rate_time.cgi
+++ b/httemplate/edit/rate_time.cgi
@@ -15,12 +15,34 @@
<TD><INPUT TYPE="text" NAME="ratetimename" VALUE="<% $rate_time ? $rate_time->ratetimename : '' %>"></TD>
</TR>
</TABLE>
-<% include('/elements/auto-table.html',
- 'header' => [ '', 'Start','','', '','End','','' ],
- 'fields' => [ qw(sd sh sm sa ed eh em ea) ],
- 'select' => [ ($day, $hour, $min, $ampm) x 2 ],
- 'data' => \@data,
- ) %>
+<TABLE>
+ <TR>
+ <TH COLSPAN=4 ALIGN="center">Start</TH>
+ <TH COLSPAN=4 ALIGN="center">End</TH>
+ </TR>
+ <TR id="mytemplate">
+% for my $pre (qw(s e)) {
+% for my $f (qw(d h m a)) { # day, hour, minute, am/pm
+ <TD>
+ <SELECT NAME="<%$pre.$f%>">
+% my $i = 0;
+% while ($i < @{ $choices{$f} }) {
+ <OPTION VALUE="<%$choices{$f}[$i]%>">
+% $i++;
+ <%$choices{$f}[$i]%></OPTION>
+% $i++;
+% }
+ </SELECT>
+ </TD>
+% } #$f
+% } #$pre
+ </TR>
+<& /elements/auto-table.html,
+ 'template_row' => 'mytemplate',
+ 'data' => \@data,
+ 'fieldorder' => [qw(sd sh sm sa ed eh em ea)],
+&>
+</TABLE>
<INPUT TYPE="submit" VALUE="<% $rate_time ? 'Apply changes' : 'Add period'%>">
</FORM>
<BR>
@@ -42,7 +64,12 @@ my $day = [ 0 => 'Sun',
my $hour = [ map( {$_, sprintf('%02d',$_) } 12, 1..11 )];
my $min = [ map( {$_, sprintf('%02d',$_) } 0,30 )];
my $ampm = [ 0 => 'AM', 1 => 'PM' ];
-
+my %choices = (
+ 'd' => $day,
+ 'h' => $hour,
+ 'm' => $min,
+ 'a' => $ampm,
+);
if($ratetimenum) {
$action = 'Edit';
$rate_time = qsearchs('rate_time', {ratetimenum => $ratetimenum})