diff options
Diffstat (limited to 'httemplate/edit')
66 files changed, 5779 insertions, 0 deletions
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi new file mode 100755 index 000000000..d9b7579f6 --- /dev/null +++ b/httemplate/edit/REAL_cust_pkg.cgi @@ -0,0 +1,131 @@ +<!-- mason kludge --> +<% +# <!-- $Id: REAL_cust_pkg.cgi,v 1.7 2003-11-19 12:21:09 ivan Exp $ --> + +my $error =''; +my $pkgnum = ''; +if ( $cgi->param('error') ) { + $error = $cgi->param('error'); + $pkgnum = $cgi->param('pkgnum'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/ or die "no pkgnum"; + $pkgnum = $1; +} + +#get package record +my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); +die "No package!" unless $cust_pkg; +my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->getfield('pkgpart')}); + +if ( $error ) { + #$cust_pkg->$_(str2time($cgi->param($_)) foreach qw(setup bill); + $cust_pkg->setup(str2time($cgi->param('setup'))); + $cust_pkg->bill(str2time($cgi->param('bill'))); +} + +#my $custnum = $cust_pkg->getfield('custnum'); +print header('Package Edit'); #, menubar( +# "View this customer (#$custnum)" => popurl(2). "view/cust_main.cgi?$custnum", +# 'Main Menu' => popurl(2) +#)); + +%> + + <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2"> + <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT> + <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT> + <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT> + +<% + +#print info +my($susp,$cancel,$expire)=( + $cust_pkg->getfield('susp'), + $cust_pkg->getfield('cancel'), + $cust_pkg->getfield('expire'), +); +my($pkg,$comment)=($part_pkg->getfield('pkg'),$part_pkg->getfield('comment')); +my($setup,$bill)=($cust_pkg->getfield('setup'),$cust_pkg->getfield('bill')); +my $otaker = $cust_pkg->getfield('otaker'); + +print '<FORM NAME="formname" ACTION="process/REAL_cust_pkg.cgi" METHOD="POST">', qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!; + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>! + if $error; + +#my $format = "%c %z (%Z)"; +my $format = "%m/%d/%Y %T %z (%Z)"; + +print ntable("#cccccc",2), + '<TR><TD ALIGN="right">Package number</TD><TD BGCOLOR="#ffffff">', + $pkgnum, '</TD></TR>', + '<TR><TD ALIGN="right">Package</TD><TD BGCOLOR="#ffffff">', + $pkg, '</TD></TR>', + '<TR><TD ALIGN="right">Comment</TD><TD BGCOLOR="#ffffff">', + $comment, '</TD></TR>', + '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">', + $otaker, '</TD></TR>', + '<TR><TD ALIGN="right">Setup date</TD><TD>'. + '<INPUT TYPE="text" NAME="setup" SIZE=32 ID="setup_text" VALUE="', + ( $setup ? time2str($format, $setup) : "" ), '">'. + ' <IMG SRC="../images/calendar.png" ID="setup_button" STYLE="cursor: pointer" TITLE="Select date">'. + '</TD></TR>'; + +print '<TR><TD ALIGN="right">Last bill date</TD><TD>', + '<INPUT TYPE="text" NAME="last_bill" SIZE=32 ID="last_bill_text" VALUE="', + ( $cust_pkg->last_bill + ? time2str($format, $cust_pkg->last_bill) + : "" ), + '">'. + ' <IMG SRC="../images/calendar.png" ID="last_bill_button" STYLE="cursor: pointer" TITLE="Select date">'. + '</TD></TR>' + if $cust_pkg->dbdef_table->column('last_bill'); + +print '<TR><TD ALIGN="right">Next bill date</TD><TD>', + '<INPUT TYPE="text" NAME="bill" SIZE=32 ID="bill_text" VALUE="', + ( $bill ? time2str($format, $bill) : "" ), '">'. + ' <IMG SRC="../images/calendar.png" ID="bill_button" STYLE="cursor: pointer" TITLE="Select date">'. + '</TD></TR>'; + +print '<TR><TD ALIGN="right">Suspension date</TD><TD BGCOLOR="#ffffff">', + time2str($format, $susp), '</TD></TR>' + if $susp; + +#print '<TR><TD ALIGN="right">Expiration date</TD><TD BGCOLOR="#ffffff">', +# time2str("%D",$expire), '</TD></TR>' +# if $expire; +print '<TR><TD ALIGN="right">Expiration date'. + '</TD><TD>', + '<INPUT TYPE="text" NAME="expire" SIZE=32 ID="expire_text" VALUE="', + ( $expire ? time2str($format, $expire) : "" ), '">'. + ' <IMG SRC="../images/calendar.png" ID="expire_button" STYLE="cursor: pointer" TITLE="Select date">'. + '<BR><FONT SIZE=-1>(will <b>cancel</b> this package'. + ' when the date is reached)</FONT>'. + '</TD></TR>'; + +print '<TR><TD ALIGN="right">Cancellation date</TD><TD BGCOLOR="#ffffff">', + time2str($format, $cancel), '</TD></TR>' + if $cancel; + +%> +</TABLE> +<SCRIPT TYPE="text/javascript"> +<% + my @cal = qw( setup bill expire ); + push @cal, 'last_bill' + if $cust_pkg->dbdef_table->column('last_bill'); + foreach my $cal (@cal) { +%> + Calendar.setup({ + inputField: "<%= $cal %>_text", + ifFormat: "%m/%d/%Y", + button: "<%= $cal %>_button", + align: "BR" + }); +<% } %> +</SCRIPT> +<BR><INPUT TYPE="submit" VALUE="Apply Changes"> +</FORM> +</BODY> +</HTML> diff --git a/httemplate/edit/agent.cgi b/httemplate/edit/agent.cgi new file mode 100755 index 000000000..8a1cb2ae1 --- /dev/null +++ b/httemplate/edit/agent.cgi @@ -0,0 +1,79 @@ +<!-- mason kludge --> +<% + +my $agent; +if ( $cgi->param('error') ) { + $agent = new FS::agent ( { + map { $_, scalar($cgi->param($_)) } fields('agent') + } ); +} elsif ( $cgi->keywords ) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $agent = qsearchs( 'agent', { 'agentnum' => $1 } ); +} else { #adding + $agent = new FS::agent {}; +} +my $action = $agent->agentnum ? 'Edit' : 'Add'; +my $hashref = $agent->hashref; + +%> + +<%= header("$action Agent", menubar( + 'Main Menu' => $p, + 'View all agents' => $p. 'browse/agent.cgi', +)) %> + +<% if ( $cgi->param('error') ) { %> +<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT> +<% } %> + +<FORM ACTION="<%=popurl(1)%>process/agent.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $hashref->{agentnum} %>"> +Agent #<%= $hashref->{agentnum} ? $hashref->{agentnum} : "(NEW)" %> + +<%= &ntable("#cccccc", 2, '') %> +<TR> + <TH ALIGN="right">Agent</TH> + <TD><INPUT TYPE="text" NAME="agent" SIZE=32 VALUE="<%= $hashref->{agent} %>"></TD> +</TR> +<TR> + <TH ALIGN="right">Agent type</TH> + <TD><SELECT NAME="typenum" SIZE=1> + +<% foreach my $agent_type (qsearch('agent_type',{})) { %> + <OPTION VALUE="<%= $agent_type->typenum %>"<%= ( $hashref->{typenum} && ( $hashref->{typenum} == $agent_type->typenum ) ) ? ' SELECTED' : '' %>> + <%= $agent_type->getfield('typenum') %>: <%= $agent_type->getfield('atype') %> +<% } %> + +</SELECT></TD> +</TR> +<% if ( dbdef->table('agent')->column('disabled') ) { %> + <TR> + <TD ALIGN="right">Disable</TD> + <TD><INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>></TD> + </TR> +<% } %> +<TR> + <TD ALIGN="right"><!--Frequency--></TD> + <TD><INPUT TYPE="hidden" NAME="freq" VALUE="<%= $hashref->{freq} %>"></TD> +</TR> +<TR> + <TD ALIGN="right"><!--Program--></TD> + <TD><INPUT TYPE="hidden" NAME="prog" VALUE="<%= $hashref->{prog} %>"></TD> +</TR> +<% if ( dbdef->table('agent')->column('username') ) { %> + <TR> + <TD ALIGN="right">Agent interface username</TD> + <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $hashref->{username} %>"></TD> + </TR> + <TR> + <TD ALIGN="right">Agent interface password</TD> + <TD><INPUT TYPE="text" NAME="_password" VALUE="<%= $hashref->{_password} %>"></TD> + </TR> +<% } %> +</TABLE> + +<BR><INPUT TYPE="submit" VALUE="<%= $hashref->{agentnum} ? "Apply changes" : "Add agent" %>"> + </FORM> + </BODY> +</HTML> diff --git a/httemplate/edit/agent_type.cgi b/httemplate/edit/agent_type.cgi new file mode 100755 index 000000000..637c710ab --- /dev/null +++ b/httemplate/edit/agent_type.cgi @@ -0,0 +1,63 @@ +<!-- mason kludge --> +<% + +my($agent_type); +if ( $cgi->param('error') ) { + $agent_type = new FS::agent_type ( { + map { $_, scalar($cgi->param($_)) } fields('agent') + } ); +} elsif ( $cgi->keywords ) { #editing + my( $query ) = $cgi->keywords; + $query =~ /^(\d+)$/; + $agent_type=qsearchs('agent_type',{'typenum'=>$1}); +} else { #adding + $agent_type = new FS::agent_type {}; +} +my $action = $agent_type->typenum ? 'Edit' : 'Add'; +my $hashref = $agent_type->hashref; + +print header("$action Agent Type", menubar( + 'Main Menu' => "$p", + 'View all agent types' => "${p}browse/agent_type.cgi", +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print '<FORM ACTION="', popurl(1), 'process/agent_type.cgi" METHOD=POST>', + qq!<INPUT TYPE="hidden" NAME="typenum" VALUE="$hashref->{typenum}">!, + "Agent Type #", $hashref->{typenum} ? $hashref->{typenum} : "(NEW)"; + +print <<END; +<BR><BR>Agent Type <INPUT TYPE="text" NAME="atype" SIZE=32 VALUE="$hashref->{atype}"> +<BR><BR>Select which packages agents of this type may sell to customers<BR> +END + +foreach my $part_pkg ( qsearch('part_pkg',{ 'disabled' => '' }) ) { + print qq!<BR><INPUT TYPE="checkbox" NAME="pkgpart!, + $part_pkg->getfield('pkgpart'), qq!" !, + # ( 'CHECKED 'x scalar( + qsearchs('type_pkgs',{ + 'typenum' => $agent_type->getfield('typenum'), + 'pkgpart' => $part_pkg->getfield('pkgpart'), + }) + ? 'CHECKED ' + : '', + qq!VALUE="ON"> !, + qq!<A HREF="${p}edit/part_pkg.cgi?!, $part_pkg->pkgpart, + '">', $part_pkg->pkgpart. ": ". $part_pkg->getfield('pkg'), '</A>', + ; +} + +print qq!<BR><BR><INPUT TYPE="submit" VALUE="!, + $hashref->{typenum} ? "Apply changes" : "Add agent type", + qq!">!; + +print <<END; + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_bill_pay.cgi b/httemplate/edit/cust_bill_pay.cgi new file mode 100755 index 000000000..24bce308a --- /dev/null +++ b/httemplate/edit/cust_bill_pay.cgi @@ -0,0 +1,95 @@ +<!-- mason kludge --> +<% + +my($paynum, $amount, $invnum); +if ( $cgi->param('error') ) { + $paynum = $cgi->param('paynum'); + $amount = $cgi->param('amount'); + $invnum = $cgi->param('invnum'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $paynum = $1; + $amount = ''; + $invnum = ''; +} + +my $otaker = getotaker; + +my $p1 = popurl(1); + +print header("Apply Payment", ''); +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT><BR><BR>" + if $cgi->param('error'); +print <<END; + <FORM ACTION="${p1}process/cust_bill_pay.cgi" METHOD=POST> +END + +my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); +die "payment $paynum not found!" unless $cust_pay; + +my $unapplied = $cust_pay->unapplied; + +print "Payment # <B>$paynum</B>". + qq!<INPUT TYPE="hidden" NAME="paynum" VALUE="$paynum">!. + '<BR>Date: <B>'. time2str("%D", $cust_pay->_date). '</B>'. + '<BR>Amount: $<B>'. $cust_pay->paid. '</B>'. + "<BR>Unapplied amount: \$<B>$unapplied</B>" + ; + +my @cust_bill = grep $_->owed != 0, + qsearch('cust_bill', { 'custnum' => $cust_pay->custnum } ); + +print <<END; +<SCRIPT> +function changed(what) { + cust_bill = what.options[what.selectedIndex].value; +END + +foreach my $cust_bill ( @cust_bill ) { + my $invnum = $cust_bill->invnum; + my $changeto = $cust_bill->owed < $unapplied + ? $cust_bill->owed + : $unapplied; + print <<END; + if ( cust_bill == $invnum ) { + what.form.amount.value = "$changeto"; + } +END +} + +print <<END; + if ( cust_bill == "Refund" ) { + what.form.amount.value = "$unapplied"; + } +} +</SCRIPT> +END + +print qq!<BR>Invoice #<SELECT NAME="invnum" SIZE=1 onChange="changed(this)">!, + '<OPTION VALUE="">'; +foreach my $cust_bill ( @cust_bill ) { + print '<OPTION'. ( $cust_bill->invnum eq $invnum ? ' SELECTED' : '' ). + ' VALUE="'. $cust_bill->invnum. '">'. $cust_bill->invnum. + ' - '. time2str("%D",$cust_bill->_date). + ' - $'. $cust_bill->owed; +} +print qq!<OPTION VALUE="Refund">Refund!; +print "</SELECT>"; + +print qq!<BR>Amount \$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8>!; + +print <<END; +<BR> +<INPUT TYPE="submit" VALUE="Apply"> +END + +print <<END; + + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi new file mode 100755 index 000000000..aae0df2fc --- /dev/null +++ b/httemplate/edit/cust_credit.cgi @@ -0,0 +1,63 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; +my($custnum, $amount, $reason); +if ( $cgi->param('error') ) { + #$cust_credit = new FS::cust_credit ( { + # map { $_, scalar($cgi->param($_)) } fields('cust_credit') + #} ); + $custnum = $cgi->param('custnum'); + $amount = $cgi->param('amount'); + #$refund = $cgi->param('refund'); + $reason = $cgi->param('reason'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $custnum = $1; + $amount = ''; + #$refund = 'yes'; + $reason = ''; +} +my $_date = time; + +my $otaker = getotaker; + +my $p1 = popurl(1); + +print header("Post Credit", ''); +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); +print <<END, small_custview($custnum, $conf->config('countrydefault')); + <FORM ACTION="${p1}process/cust_credit.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="crednum" VALUE=""> + <INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum"> + <INPUT TYPE="hidden" NAME="paybatch" VALUE=""> + <INPUT TYPE="hidden" NAME="_date" VALUE="$_date"> + <INPUT TYPE="hidden" NAME="credited" VALUE=""> + <INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker"> +END + +print '<BR><BR>Credit'. ntable("#cccccc", 2). + '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'. + time2str("%D",$_date). '</TD></TR>'; + +print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8></TD></TR>!; + +#print qq! <INPUT TYPE="checkbox" NAME="refund" VALUE="$refund">Also post refund!; + +print qq!<TR><TD ALIGN="right">Reason</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="reason" VALUE="$reason"></TD></TR>!; + +print qq!<TR><TD ALIGN="right">Auto-apply<BR>to invoices</TD><TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD>!; + +print <<END; +</TABLE> +<BR> +<INPUT TYPE="submit" VALUE="Post credit"> + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_credit_bill.cgi b/httemplate/edit/cust_credit_bill.cgi new file mode 100755 index 000000000..1a97e1312 --- /dev/null +++ b/httemplate/edit/cust_credit_bill.cgi @@ -0,0 +1,101 @@ +<!-- mason kludge --> +<% + +my($crednum, $amount, $invnum); +if ( $cgi->param('error') ) { + #$cust_credit_bill = new FS::cust_credit_bill ( { + # map { $_, scalar($cgi->param($_)) } fields('cust_credit_bill') + #} ); + $crednum = $cgi->param('crednum'); + $amount = $cgi->param('amount'); + #$refund = $cgi->param('refund'); + $invnum = $cgi->param('invnum'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $crednum = $1; + $amount = ''; + #$refund = 'yes'; + $invnum = ''; +} + +my $otaker = getotaker; + +my $p1 = popurl(1); + +print header("Apply Credit", ''); +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT><BR><BR>" + if $cgi->param('error'); +print <<END; + <FORM ACTION="${p1}process/cust_credit_bill.cgi" METHOD=POST> +END + +my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } ); +die "credit $crednum not found!" unless $cust_credit; + +my $credited = $cust_credit->credited; + +print "Credit # <B>$crednum</B>". + qq!<INPUT TYPE="hidden" NAME="crednum" VALUE="$crednum">!. + '<BR>Date: <B>'. time2str("%D", $cust_credit->_date). '</B>'. + '<BR>Amount: $<B>'. $cust_credit->amount. '</B>'. + "<BR>Unapplied amount: \$<B>$credited</B>". + '<BR>Reason: <B>'. $cust_credit->reason. '</B>' + ; + +my @cust_bill = grep $_->owed != 0, + qsearch('cust_bill', { 'custnum' => $cust_credit->custnum } ); + +print <<END; +<SCRIPT> +function changed(what) { + cust_bill = what.options[what.selectedIndex].value; +END + +foreach my $cust_bill ( @cust_bill ) { + my $invnum = $cust_bill->invnum; + my $changeto = $cust_bill->owed < $cust_credit->credited + ? $cust_bill->owed + : $cust_credit->credited; + print <<END; + if ( cust_bill == $invnum ) { + what.form.amount.value = "$changeto"; + } +END +} + +print <<END; + if ( cust_bill == "Refund" ) { + what.form.amount.value = "$credited"; + } +} +</SCRIPT> +END + +print qq!<BR>Invoice #<SELECT NAME="invnum" SIZE=1 onChange="changed(this)">!, + '<OPTION VALUE="">'; +foreach my $cust_bill ( @cust_bill ) { + print '<OPTION'. ( $cust_bill->invnum eq $invnum ? ' SELECTED' : '' ). + ' VALUE="'. $cust_bill->invnum. '">'. $cust_bill->invnum. + ' - '. time2str("%D",$cust_bill->_date). + ' - $'. $cust_bill->owed; +} +print qq!<OPTION VALUE="Refund">Refund!; +print "</SELECT>"; + +print qq!<BR>Amount \$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8>!; + +print <<END; +<BR> +<INPUT TYPE="submit" VALUE="Apply"> +END + +print <<END; + + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi new file mode 100755 index 000000000..f5826f31b --- /dev/null +++ b/httemplate/edit/cust_main.cgi @@ -0,0 +1,574 @@ +<!-- mason kludge --> +<% + + #for misplaced logic below + #use FS::part_pkg; + + #for false laziness below (now more properly lazy) + #use FS::svc_acct_pop; + + #for (other) false laziness below + #use FS::agent; + #use FS::type_pkgs; + +my $conf = new FS::Conf; + +#get record + +my $error = ''; +my($custnum, $username, $password, $popnum, $cust_main, $saved_pkgpart); +my(@invoicing_list); +if ( $cgi->param('error') ) { + $error = $cgi->param('error'); + $cust_main = new FS::cust_main ( { + map { $_, scalar($cgi->param($_)) } fields('cust_main') + } ); + $custnum = $cust_main->custnum; + $saved_pkgpart = $cgi->param('pkgpart_svcpart') || ''; + if ( $saved_pkgpart =~ /^(\d+)_/ ) { + $saved_pkgpart = $1; + } else { + $saved_pkgpart = ''; + } + $username = $cgi->param('username'); + $password = $cgi->param('_password'); + $popnum = $cgi->param('popnum'); + @invoicing_list = split( /\s*,\s*/, $cgi->param('invoicing_list') ); +} elsif ( $cgi->keywords ) { #editing + my( $query ) = $cgi->keywords; + $query =~ /^(\d+)$/; + $custnum=$1; + $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); + if ( $cust_main->dbdef_table->column('paycvv') + && length($cust_main->paycvv) ) { + my $paycvv = $cust_main->paycvv; + $paycvv =~ s/./*/g; + $cust_main->paycvv($paycvv); + } + $saved_pkgpart = 0; + $username = ''; + $password = ''; + $popnum = 0; + @invoicing_list = $cust_main->invoicing_list; +} else { + $custnum=''; + $cust_main = new FS::cust_main ( {} ); + $cust_main->otaker( &getotaker ); + $cust_main->referral_custnum( $cgi->param('referral_custnum') ); + $saved_pkgpart = 0; + $username = ''; + $password = ''; + $popnum = 0; + @invoicing_list = (); +} +$cgi->delete_all(); +my $action = $custnum ? 'Edit' : 'Add'; + +# top + +my $p1 = popurl(1); +print header("Customer $action", '', ' onUnload="myclose()"'); +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $error, "</FONT>" + if $error; + +print qq!<FORM ACTION="${p1}process/cust_main.cgi" METHOD=POST NAME="form1" onSubmit="document.form1.submit.disabled=true">!, + qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!, + qq!Customer # !, ( $custnum ? "<B>$custnum</B>" : " (NEW)" ), + +; + +# agent + +my $r = qq!<font color="#ff0000">*</font> !; + +my %agent_search = dbdef->table('agent')->column('disabled') + ? ( 'disabled' => '' ) : (); +my @agents = qsearch( 'agent', \%agent_search ); +#die "No agents created!" unless @agents; +eidiot "You have not created any agents (or all agents are disabled). You must create at least one agent before adding a customer. Go to ". popurl(2). "browse/agent.cgi and create one or more agents." unless @agents; +my $agentnum = $cust_main->agentnum || $agents[0]->agentnum; #default to first +if ( scalar(@agents) == 1 ) { + print qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$agentnum">!; +} else { + print qq!<BR><BR>${r}Agent <SELECT NAME="agentnum" SIZE="1">!; + my $agent; + foreach $agent (sort { + $a->agent cmp $b->agent; + } @agents) { + print '<OPTION VALUE="', $agent->agentnum, '"', + " SELECTED"x($agent->agentnum==$agentnum), + ">". $agent->agent; + #">", $agent->agentnum,": ", $agent->agent; + } + print "</SELECT>"; +} + +#referral + +my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0; +if ( $custnum && ! $conf->exists('editreferrals') ) { + print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!; +} else { + my(@referrals) = qsearch('part_referral',{}); + if ( scalar(@referrals) == 0 ) { + eidiot "You have not created any advertising sources. You must create at least one advertising source before adding a customer. Go to ". popurl(2). "browse/part_referral.cgi and create one or more advertising sources."; + } elsif ( scalar(@referrals) == 1 ) { + $refnum ||= $referrals[0]->refnum; + print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!; + } else { + print qq!<BR><BR>${r}Advertising source <SELECT NAME="refnum" SIZE="1">!; + print "<OPTION> " unless $refnum; + my($referral); + foreach $referral (sort { + $a->refnum <=> $b->refnum; + } @referrals) { + print "<OPTION" . " SELECTED"x($referral->refnum==$refnum), + ">", $referral->refnum, ": ", $referral->referral; + } + print "</SELECT>"; + } +} + +#referring customer + +#print qq!<BR><BR>Referring Customer: !; +my $referring_cust_main = ''; +if ( $cust_main->referral_custnum + and $referring_cust_main = + qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) +) { + print '<BR><BR>Referring Customer: <A HREF="'. popurl(1). '/cust_main.cgi?'. + $cust_main->referral_custnum. '">'. + $cust_main->referral_custnum. ': '. + ( $referring_cust_main->company + || $referring_cust_main->last. ', '. $referring_cust_main->first ). + '</A><INPUT TYPE="hidden" NAME="referral_custnum" VALUE="'. + $cust_main->referral_custnum. '">'; +} elsif ( ! $conf->exists('disable_customer_referrals') ) { + print '<BR><BR>Referring customer number: <INPUT TYPE="text" NAME="referral_custnum" VALUE="">'; +} else { + print '<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="">'; +} + +# contact info + +my($last,$first,$ss,$company,$address1,$address2,$city,$zip)=( + $cust_main->last, + $cust_main->first, + $cust_main->ss, + $cust_main->company, + $cust_main->address1, + $cust_main->address2, + $cust_main->city, + $cust_main->zip, +); + +print "<BR><BR>Billing address", &itable("#cccccc"), <<END; +<TR><TH ALIGN="right">${r}Contact name<BR>(last, first)</TH><TD COLSPAN=3> +END + +print <<END; +<INPUT TYPE="text" NAME="last" VALUE="$last" onChange="changed(this)"> , +<INPUT TYPE="text" NAME="first" VALUE="$first" onChange="changed(this)"> +</TD> +END + +if ( $conf->exists('show_ss') ) { + print qq!<TD ALIGN="right">SS#</TD><TD><INPUT TYPE="text" NAME="ss" VALUE="$ss" SIZE=11></TD>!; +} else { + print qq!<TD><INPUT TYPE="hidden" NAME="ss" VALUE="$ss"></TD>!; +} + +print <<END; +</TR> +<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="company" VALUE="$company" SIZE=70 onChange="changed(this)"></TD></TR> +<TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=70 onChange="changed(this)"></TD></TR> +<TR><TD ALIGN="right"> </TD><TD COLSPAN=5><INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=70 onChange="changed(this)"></TD></TR> +<TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="city" VALUE="$city" onChange="changed(this)"></TD><TH ALIGN="right">${r}State</TH><TD> +END + +#false laziness with ship state +my $countrydefault = $conf->config('countrydefault') || 'US'; +$cust_main->country( $countrydefault ) unless $cust_main->country; + +my $statedefault = $conf->config('statedefault') + || ($countrydefault eq 'US' ? 'CA' : ''); +$cust_main->state( $statedefault ) + unless $cust_main->state || $cust_main->country ne $countrydefault; + +my($county_html, $state_html, $country_html) = + FS::cust_main_county::regionselector( $cust_main->county, + $cust_main->state, + $cust_main->country ); + +print "$county_html $state_html"; + +print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10 onChange="changed(this)"></TD></TR>!; + +my($daytime,$night,$fax)=( + $cust_main->daytime, + $cust_main->night, + $cust_main->fax, + '', + 'changed(this)', +); + +my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone'; +my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone'; + +print <<END; +<TR><TH ALIGN="right">${r}Country</TH><TD>$country_html</TD></TR> +<TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18 onChange="changed(this)"></TD></TR> +<TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18 onChange="changed(this)"></TD></TR> +<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12 onChange="changed(this)"></TD></TR> +END + +print "</TABLE>${r}required fields<BR>"; + +# service address + +if ( defined $cust_main->dbdef_table->column('ship_last') ) { + + print "\n", <<END; + <SCRIPT> + function changed(what) { + what.form.same.checked = false; + } + function samechanged(what) { + if ( what.checked ) { +END +print " what.form.ship_$_.value = what.form.$_.value;\n" + for (qw( last first company address1 address2 city zip daytime night fax )); +print <<END; + what.form.ship_country.selectedIndex = what.form.country.selectedIndex; + ship_country_changed(what.form.ship_country); + what.form.ship_state.selectedIndex = what.form.state.selectedIndex; + ship_state_changed(what.form.ship_state); + what.form.ship_county.selectedIndex = what.form.county.selectedIndex; + } + } + </SCRIPT> +END + + print '<BR>Service address ', + '(<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)"'; + unless ( $cust_main->ship_last && $cgi->param('same') ne 'Y' ) { + print ' CHECKED'; + foreach ( + qw( last first company address1 address2 city county state zip country + daytime night fax ) + ) { + $cust_main->set("ship_$_", $cust_main->get($_) ); + } + } + print '>same as billing address)<BR>'; + + my($ship_last,$ship_first,$ship_company,$ship_address1,$ship_address2,$ship_city,$ship_zip)=( + $cust_main->ship_last, + $cust_main->ship_first, + $cust_main->ship_company, + $cust_main->ship_address1, + $cust_main->ship_address2, + $cust_main->ship_city, + $cust_main->ship_zip, + ); + + print &itable("#cccccc"), <<END; + <TR><TH ALIGN="right">${r}Contact name<BR>(last, first)</TH><TD COLSPAN=5> +END + + print <<END; + <INPUT TYPE="text" NAME="ship_last" VALUE="$ship_last" onChange="changed(this)"> , + <INPUT TYPE="text" NAME="ship_first" VALUE="$ship_first" onChange="changed(this)"> +END + + print <<END; + </TD></TR> + <TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_company" VALUE="$ship_company" SIZE=70 onChange="changed(this)"></TD></TR> + <TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address1" VALUE="$ship_address1" SIZE=70 onChange="changed(this)"></TD></TR> + <TR><TD ALIGN="right"> </TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address2" VALUE="$ship_address2" SIZE=70 onChange="changed(this)"></TD></TR> + <TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="ship_city" VALUE="$ship_city" onChange="changed(this)"></TD><TH ALIGN="right">${r}State</TH><TD> +END + + #false laziness with regular state + $cust_main->ship_country( $countrydefault ) unless $cust_main->ship_country; + + $cust_main->ship_state( $statedefault ) + unless $cust_main->ship_state + || $cust_main->ship_country ne $countrydefault; + + my($ship_county_html, $ship_state_html, $ship_country_html) = + FS::cust_main_county::regionselector( $cust_main->ship_county, + $cust_main->ship_state, + $cust_main->ship_country, + 'ship_', + 'changed(this)', ); + + print "$ship_county_html $ship_state_html"; + + print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="ship_zip" VALUE="$ship_zip" SIZE=10 onChange="changed(this)"></TD></TR>!; + + my($ship_daytime,$ship_night,$ship_fax)=( + $cust_main->ship_daytime, + $cust_main->ship_night, + $cust_main->ship_fax, + ); + + print <<END; + <TR><TH ALIGN="right">${r}Country</TH><TD>$ship_country_html</TD></TR> + <TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_daytime" VALUE="$ship_daytime" SIZE=18 onChange="changed(this)"></TD></TR> + <TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_night" VALUE="$ship_night" SIZE=18 onChange="changed(this)"></TD></TR> + <TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_fax" VALUE="$ship_fax" SIZE=12 onChange="changed(this)"></TD></TR> +END + + print "</TABLE>${r}required fields<BR>"; + +} + +# billing info + +sub expselect { + my $prefix = shift; + my( $m, $y ) = (0, 0); + if ( scalar(@_) ) { + my $date = shift || '01-2000'; + if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format + ( $m, $y ) = ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $m, $y ) = ( $1, $3 ); + } else { + die "unrecognized expiration date format: $date"; + } + } + + my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!; + for ( 1 .. 12 ) { + $return .= "<OPTION"; + $return .= " SELECTED" if $_ == $m; + $return .= ">$_"; + } + $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!; + my @t = localtime; + my $thisYear = $t[5] + 1900; + for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. 2037 ) { + $return .= "<OPTION"; + $return .= " SELECTED" if $_ == $y; + $return .= ">$_"; + } + $return .= "</SELECT>"; + + $return; +} + +my $payby_default = $conf->config('payby-default'); + +if ( $payby_default eq 'HIDE' ) { + + $cust_main->payby('BILL') unless $cust_main->payby; + + foreach my $field (qw( tax payby )) { + print qq!<INPUT TYPE="hidden" NAME="$field" VALUE="!. + $cust_main->getfield($field). '">'; + } + + print qq!<INPUT TYPE="hidden" NAME="invoicing_list" VALUE="!. + join(', ', $cust_main->invoicing_list). '">'; + + foreach my $payby (qw( CARD DCRD CHEK DCHK LECB BILL COMP )) { + foreach my $field (qw( payinfo payname )) { + print qq!<INPUT TYPE="hidden" NAME="${payby}_$field" VALUE="!. + $cust_main->getfield($field). '">'; + } + + #false laziness w/expselect + my( $m, $y ); + my $date = $cust_main->paydate || '12-2037'; + if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format + ( $m, $y ) = ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $m, $y ) = ( $1, $3 ); + } else { + die "unrecognized expiration date format: $date"; + } + + print qq!<INPUT TYPE="hidden" NAME="${payby}_month" VALUE="$m">!. + qq!<INPUT TYPE="hidden" NAME="${payby}_year" VALUE="$y">!; + + } + +} else { + + print "<BR>Billing information", &itable("#cccccc"), + qq!<TR><TD><INPUT TYPE="checkbox" NAME="tax" VALUE="Y"!; + print qq! CHECKED! if $cust_main->tax eq "Y"; + print qq!>Tax Exempt</TD></TR><TR><TD>!. + qq!<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"!; + + #my @invoicing_list = $cust_main->invoicing_list; + print qq! CHECKED! + if ( ! @invoicing_list && ! $conf->exists('disablepostalinvoicedefault') ) + || grep { $_ eq 'POST' } @invoicing_list; + print qq!>Postal mail invoice</TD></TR>!; + my $invoicing_list = join(', ', grep { $_ ne 'POST' } @invoicing_list ); + print qq!<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="$invoicing_list"></TD></TR>!; + + print "<TR><TD>Billing type</TD></TR>", + "</TABLE>", '<SCRIPT> + var mywindow = -1; + function myopen(filename,windowname,properties) { + myclose(); + mywindow = window.open(filename,windowname,properties); + } + function myclose() { + if ( mywindow != -1 ) + mywindow.close(); + mywindow = -1; + } + var achwindow = -1; + function achopen(filename,windowname,properties) { + achclose(); + achwindow = window.open(filename,windowname,properties); + } + function achclose() { + if ( achwindow != -1 ) + achwindow.close(); + achwindow = -1; + } + </SCRIPT>', + &table("#cccccc"), "<TR>"; + + my($payinfo, $payname)=( + $cust_main->payinfo, + $cust_main->payname, + ); + + my %payby = ( + 'CARD' => qq!Credit card (automatic)<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD"). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!, + 'DCRD' => qq!Credit card (on-demand)<BR>${r}<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR>${r}Exp !. expselect("DCRD"). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!, + 'CHEK' => qq!Electronic check (automatic)<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE=""><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!, + 'DCHK' => qq!Electronic check (on-demand)<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE=""><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!, + 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!, + 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="">!, + 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR>${r}Exp !. expselect("COMP"), +); + + if ( $cust_main->dbdef_table->column('paycvv') ) { + foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 bs + $payby{$payby} .= qq!<BR>CVV2 (<A HREF="javascript:myopen('../docs/cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>) <INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!; + } + } + + my( $account, $aba ) = split('@', $payinfo); + + my %paybychecked = ( + 'CARD' => qq!Credit card (automatic)<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD", $cust_main->paydate). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!, + 'DCRD' => qq!Credit card (on-demand)<BR>${r}<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR>${r}Exp !. expselect("DCRD", $cust_main->paydate). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!, + 'CHEK' => qq!Electronic check (automatic)<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account"><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!, + 'DCHK' => qq!Electronic check (on-demand)<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account"><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!, + 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!, + 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!, + 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR>${r}Exp !. expselect("COMP", $cust_main->paydate), +); + + if ( $cust_main->dbdef_table->column('paycvv') ) { + my $paycvv = $cust_main->paycvv; + + foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 bs + $paybychecked{$payby} .= qq!<BR>CVV2 (<A HREF="javascript:myopen('../docs/cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>) <INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!; + } + } + + + $cust_main->payby($payby_default) unless $cust_main->payby; + for (qw(CARD DCRD CHEK DCHK LECB BILL COMP)) { + print qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!; + if ($cust_main->payby eq "$_") { + print qq! CHECKED> $paybychecked{$_}</TD>!; + } else { + print qq!> $payby{$_}</TD>!; + } + } + + print "</TR></TABLE>$r required fields for each billing type"; + +} + +if ( defined $cust_main->dbdef_table->column('comments') ) { + print "<BR><BR>Comments", &itable("#cccccc"), + qq!<TR><TD><TEXTAREA COLS=80 ROWS=5 WRAP="HARD" NAME="comments">!, + $cust_main->comments, "</TEXTAREA>", + "</TD></TR></TABLE>"; +} + +unless ( $custnum ) { + # pry the wrong place for this logic. also pretty expensive + #use FS::part_pkg; + + #false laziness, copied from FS::cust_pkg::order + my $pkgpart; + if ( scalar(@agents) == 1 ) { + # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART + my($agent)=qsearchs('agent',{'agentnum'=> $agentnum }); + $pkgpart = $agent->pkgpart_hashref; + } else { + #can't know (agent not chosen), so, allow all + my %typenum; + foreach my $agent ( @agents ) { + next if $typenum{$agent->typenum}++; + #fixed in 5.004_05 #$pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref } + foreach ( keys %{ $agent->pkgpart_hashref } ) { $pkgpart->{$_}++; } #5.004_04 workaround + } + } + #eslaf + + my @part_pkg = grep { $_->svcpart('svc_acct') && $pkgpart->{ $_->pkgpart } } + qsearch( 'part_pkg', { 'disabled' => '' } ); + + if ( @part_pkg ) { + +# print "<BR><BR>First package", &itable("#cccccc", "0 ALIGN=LEFT"), +#apiabuse & undesirable wrapping + print "<BR><BR>First package", &itable("#cccccc"), + qq!<TR><TD COLSPAN=2><SELECT NAME="pkgpart_svcpart">!; + + print qq!<OPTION VALUE="">(none)!; + + foreach my $part_pkg ( @part_pkg ) { + print qq!<OPTION VALUE="!, +# $part_pkg->pkgpart. "_". $pkgpart{ $part_pkg->pkgpart }, '"'; + $part_pkg->pkgpart. "_". $part_pkg->svcpart('svc_acct'), '"'; + print " SELECTED" if $saved_pkgpart && ( $part_pkg->pkgpart == $saved_pkgpart ); + print ">", $part_pkg->pkg, " - ", $part_pkg->comment; + } + print "</SELECT></TD></TR>"; + + #false laziness: (mostly) copied from edit/svc_acct.cgi + #$ulen = $svc_acct->dbdef_table->column('username')->length; + my $ulen = dbdef->table('svc_acct')->column('username')->length; + my $ulen2 = $ulen+2; + my $passwordmax = $conf->config('passwordmax') || 8; + my $pmax2 = $passwordmax + 2; + print <<END; +<TR><TD ALIGN="right">Username</TD> +<TD><INPUT TYPE="text" NAME="username" VALUE="$username" SIZE=$ulen2 MAXLENGTH=$ulen></TD></TR> +<TR><TD ALIGN="right">Password</TD> +<TD><INPUT TYPE="text" NAME="_password" VALUE="$password" SIZE=$pmax2 MAXLENGTH=$passwordmax> +(blank to generate)</TD></TR> +END + + print '<TR><TD ALIGN="right">Access number</TD><TD WIDTH="100%">' + . + &FS::svc_acct_pop::popselector($popnum). + '</TD></TR></TABLE>' + ; + } +} + +my $otaker = $cust_main->otaker; +print qq!<INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">!, + qq!<BR><INPUT NAME="submit" TYPE="submit" VALUE="!, + $custnum ? "Apply Changes" : "Add Customer", qq!">!, + "</FORM></BODY></HTML>", +; + +%> diff --git a/httemplate/edit/cust_main_county-expand.cgi b/httemplate/edit/cust_main_county-expand.cgi new file mode 100755 index 000000000..9f314a457 --- /dev/null +++ b/httemplate/edit/cust_main_county-expand.cgi @@ -0,0 +1,54 @@ +<!-- mason kludge --> +<% + +my($taxnum, $delim, $expansion, $taxclass ); +my($query) = $cgi->keywords; +if ( $cgi->param('error') ) { + $taxnum = $cgi->param('taxnum'); + $delim = $cgi->param('delim'); + $expansion = $cgi->param('expansion'); + $taxclass = $cgi->param('taxclass'); +} else { + $query =~ /^(taxclass)?(\d+)$/ + or die "Illegal taxnum (query $query)"; + $taxclass = $1 ? 'taxclass' : ''; + $taxnum = $2; + $delim = 'n'; + $expansion = ''; +} + +my $cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum}) + or die "cust_main_county.taxnum $taxnum not found"; +die "Can't expand entry!" if $cust_main_county->getfield('county'); + +my $p1 = popurl(1); +print header("Tax Rate (expand)", menubar( + 'Main Menu' => popurl(2), +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print <<END; + <FORM ACTION="${p1}process/cust_main_county-expand.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="taxnum" VALUE="$taxnum"> + <INPUT TYPE="hidden" NAME="taxclass" VALUE="$taxclass"> + Separate by +END +print '<INPUT TYPE="radio" NAME="delim" VALUE="n"'; +print ' CHECKED' if $delim eq 'n'; +print '>line (broken on some browsers) or', + '<INPUT TYPE="radio" NAME="delim" VALUE="s"'; +print ' CHECKED' if $delim eq 's'; +print '>whitespace.'; +print <<END; + <BR><INPUT TYPE="submit" VALUE="Submit"> + <BR><TEXTAREA NAME="expansion" ROWS=100>$expansion</TEXTAREA> + </FORM> + </CENTER> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_main_county.cgi b/httemplate/edit/cust_main_county.cgi new file mode 100755 index 000000000..4bcfcbe9b --- /dev/null +++ b/httemplate/edit/cust_main_county.cgi @@ -0,0 +1,98 @@ +<!-- mason kludge --> +<% + +print header("Edit tax rates", menubar( + 'Main Menu' => popurl(2), +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="!, popurl(1), + qq!process/cust_main_county.cgi" METHOD=POST>!, &table(), <<END; + <TR> + <TH><FONT SIZE=-1>Country</FONT></TH> + <TH><FONT SIZE=-1>State</FONT></TH> + <TH><FONT SIZE=-1>County</FONT></TH> + <TH><FONT SIZE=-1>Taxclass</FONT><BR><FONT SIZE=-2>(per-package classification)</FONT></TH> +END + +if ( dbdef->table('cust_main_county')->column('taxname') ) { + print '<TH><FONT SIZE=-1>Tax name</FONT><BR><FONT SIZE=-2>(printed on invoices)</FONT></TH>'; +} + +print <<END; + <TH><FONT SIZE=-1>Tax</FONT></TH> + <TH><FONT SIZE=-1>Exempt<BR>per<BR>month</TH> +END + +if ( dbdef->table('cust_main_county')->column('setuptax') ) { + print '<TH><FONT SIZE=-1>Setup<BR>fee<BR>exempt</TH>'; +} +if ( dbdef->table('cust_main_county')->column('recurtax') ) { + print '<TH><FONT SIZE=-1>Recurring<BR>fee<BR>exempt</TH>'; +} + +print '</TR>'; + +foreach my $cust_main_county ( sort { $a->country cmp $b->country + or $a->state cmp $b->state + or $a->county cmp $b->county + } qsearch('cust_main_county',{}) ) { + my($hashref)=$cust_main_county->hashref; + print <<END; + <TR> + <TD BGCOLOR="#ffffff">$hashref->{country}</TD> +END + + print "<TD", $hashref->{state} + ? ' BGCOLOR="#ffffff">'.$hashref->{state} + : ' BGCOLOR="#cccccc">(ALL)' + , "</TD>"; + + print "<TD", $hashref->{county} + ? ' BGCOLOR="#ffffff">'. $hashref->{county} + : ' BGCOLOR="#cccccc">(ALL)' + , "</TD>"; + + print "<TD", $hashref->{taxclass} + ? ' BGCOLOR="#ffffff">'. $hashref->{taxclass} + : ' BGCOLOR="#cccccc">(ALL)' + , "</TD>"; + + print qq!<TD><INPUT TYPE="text" NAME="taxname!, $hashref->{taxnum}, + qq!" VALUE="!, $hashref->{taxname}, qq!"></TD>! + if dbdef->table('cust_main_county')->column('taxname'); + + print qq!<TD><TABLE><TR><TD><INPUT TYPE="text" NAME="tax!, $hashref->{taxnum}, + qq!" VALUE="!, $hashref->{tax}, qq!" SIZE=6 MAXLENGTH=6></TD><TD>%</TD></TR></TABLE></TD>!; + print qq!<TD><TABLE><TR><TD>\$</TD><TD><INPUT TYPE="text" NAME="exempt_amount!, $hashref->{taxnum}, + qq!" VALUE="!, $hashref->{exempt_amount}||0, qq!" SIZE=6></TD></TR></TABLE></TD>!; + + print qq!<TD><INPUT TYPE="checkbox" NAME="setuptax!. $hashref->{taxnum}. + '" VALUE="Y"'. + ( $hashref->{setuptax} =~ /^Y$/i ? ' CHECKED' : '' ). + '></TD>' + if dbdef->table('cust_main_county')->column('setuptax'); + + print qq!<TD><INPUT TYPE="checkbox" NAME="recurtax!. $hashref->{taxnum}. + '" VALUE="Y"'. + ( $hashref->{recurtax} =~ /^Y$/i ? ' CHECKED' : '' ). + '></TD>' + if dbdef->table('cust_main_county')->column('recurtax'); + + print '</TR>'; + +} + +print <<END; + </TABLE> + <INPUT TYPE="submit" VALUE="Apply changes"> + </FORM> + </CENTER> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi new file mode 100755 index 000000000..f6ae7b299 --- /dev/null +++ b/httemplate/edit/cust_pay.cgi @@ -0,0 +1,129 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; + +my($link, $linknum, $paid, $payby, $payinfo, $quickpay); +if ( $cgi->param('error') ) { + $link = $cgi->param('link'); + $linknum = $cgi->param('linknum'); + $paid = $cgi->param('paid'); + $payby = $cgi->param('payby'); + $payinfo = $cgi->param('payinfo'); + $quickpay = $cgi->param('quickpay'); +} elsif ($cgi->keywords) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $link = 'invnum'; + $linknum = $1; + $paid = ''; + $payby = 'BILL'; + $payinfo = ""; + $quickpay = ''; +} elsif ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + $link = 'custnum'; + $linknum = $1; + $paid = ''; + $payby = 'BILL'; + $payinfo = ''; + $quickpay = $cgi->param('quickpay'); +} else { + die "illegal query ". $cgi->keywords; +} +my $_date = time; + +my $paybatch = "webui-$_date-$$-". rand() * 2**32; + +my $p1 = popurl(1); +print header("Post payment", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT><BR><BR>" + if $cgi->param('error'); + +print <<END, ntable("#cccccc",2); + <FORM ACTION="${p1}process/cust_pay.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="link" VALUE="$link"> + <INPUT TYPE="hidden" NAME="linknum" VALUE="$linknum"> + <INPUT TYPE="hidden" NAME="quickpay" VALUE="$quickpay"> +END + +my $custnum; +if ( $link eq 'invnum' ) { + + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $linknum } ) + or die "unknown invnum $linknum"; + print "Invoice #<B>$linknum</B>". ntable("#cccccc",2). + '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'. + time2str("%D", $cust_bill->_date). '</TD></TR>'. + '<TR><TD ALIGN="right" VALIGN="top">Items</TD><TD BGCOLOR="#ffffff">'; + foreach ( $cust_bill->cust_bill_pkg ) { #false laziness with FS::cust_bill + if ( $_->pkgnum ) { + + my($cust_pkg)=qsearchs('cust_pkg', { 'pkgnum', $_->pkgnum } ); + my($part_pkg)=qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->pkgpart}); + my($pkg)=$part_pkg->pkg; + + if ( $_->setup != 0 ) { + print "$pkg Setup<BR>"; # $money_char. sprintf("%10.2f",$_->setup); + print join('<BR>', + map { " ". $_->[0]. ": ". $_->[1] } $cust_pkg->labels + ). '<BR>'; + } + + if ( $_->recur != 0 ) { + print + "$pkg (" . time2str("%x",$_->sdate) . " - " . + time2str("%x",$_->edate) . ")<BR>"; + #$money_char. sprintf("%10.2f",$_->recur) + print join('<BR>', + map { '--->'. $_->[0]. ": ". $_->[1] } $cust_pkg->labels + ). '<BR>'; + } + + } else { #pkgnum Tax + print "Tax<BR>" # $money_char. sprintf("%10.2f",$_->setup) + if $_->setup != 0; + } + + } + print '</TD></TR></TABLE><BR><BR>'; + + $custnum = $cust_bill->custnum; + +} elsif ( $link eq 'custnum' ) { + $custnum = $linknum; +} + +print small_custview($custnum, $conf->config('countrydefault')); + +print qq!<INPUT TYPE="hidden" NAME="_date" VALUE="$_date">!; +print qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$payby">!; + +print '<BR><BR>Payment'. ntable("#cccccc", 2). + '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'. + time2str("%D",$_date). '</TD></TR>'; + +print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="paid" VALUE="$paid" SIZE=8 MAXLENGTH=8></TD></TR>!; + +print qq!<TR><TD ALIGN="right">Payby</TD><TD BGCOLOR="#ffffff">$payby</TD></TR>!; + +#payinfo (check # now as payby="BILL" hardcoded.. what to do later?) +print qq!<TR><TD ALIGN="right">Check #</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="payinfo" VALUE="$payinfo"></TD></TR>!; + +print qq!<TR><TD ALIGN="right">Auto-apply<BR>to invoices</TD><TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD>!; + +print "</TABLE>"; + +#paybatch +print qq!<INPUT TYPE="hidden" NAME="paybatch" VALUE="$paybatch">!; + +print <<END; +<BR> +<INPUT TYPE="submit" VALUE="Post payment"> + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/cust_pkg.cgi b/httemplate/edit/cust_pkg.cgi new file mode 100755 index 000000000..485d601eb --- /dev/null +++ b/httemplate/edit/cust_pkg.cgi @@ -0,0 +1,117 @@ +<!-- mason kludge --> +<% + +my %pkg = (); +my %comment = (); +my %all_pkg = (); +my %all_comment = (); +#foreach (qsearch('part_pkg', { 'disabled' => '' })) { +# $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); +# $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); +#} +foreach (qsearch('part_pkg', {} )) { + $all_pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); + $all_comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); + next if $_->disabled; + $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); + $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); +} + +my($custnum, %remove_pkg); +if ( $cgi->param('error') ) { + $custnum = $cgi->param('custnum'); + %remove_pkg = map { $_ => 1 } $cgi->param('remove_pkg'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $custnum = $1; + %remove_pkg = (); +} + +my $p1 = popurl(1); +print header("Add/Edit Packages", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="${p1}process/cust_pkg.cgi" METHOD=POST>!; + +print qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!; + +#current packages +my @cust_pkg = qsearch('cust_pkg',{ 'custnum' => $custnum, 'cancel' => '' } ); + +if (@cust_pkg) { + print <<END; +Current packages - select to remove (services are moved to a new package below) +<BR><BR> +END + + my $count = 0 ; + print qq!<TABLE>! ; + foreach (@cust_pkg) { + print '<TR>' if $count == 0; + my($pkgnum,$pkgpart)=( $_->getfield('pkgnum'), $_->getfield('pkgpart') ); + print qq!<TD><INPUT TYPE="checkbox" NAME="remove_pkg" VALUE="$pkgnum"!; + print " CHECKED" if $remove_pkg{$pkgnum}; + print qq!>$pkgnum: $all_pkg{$pkgpart} - $all_comment{$pkgpart}</TD>\n!; + $count ++ ; + if ($count == 2) + { + $count = 0 ; + print qq!</TR>\n! ; + } + } + print qq!</TABLE><BR><BR>!; +} + +print <<END; +Order new packages<BR><BR> +END + +my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum}); +my $agent = qsearchs('agent',{'agentnum'=> $cust_main->agentnum }); + +my $count = 0; +my $pkgparts = 0; +print qq!<TABLE>!; +foreach my $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { + $pkgparts++; + my($pkgpart)=$type_pkgs->pkgpart; + next unless exists $pkg{$pkgpart}; #skip disabled ones + print qq!<TR>! if ( $count == 0 ); + my $value = $cgi->param("pkg$pkgpart") || 0; + print <<END; + <TD> + <INPUT TYPE="text" NAME="pkg$pkgpart" VALUE="$value" SIZE="2" MAXLENGTH="2"> + $pkgpart: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n +END + $count ++ ; + if ( $count == 2 ) { + print qq!</TR>\n! ; + $count = 0; + } +} +print qq!</TABLE>!; + +unless ( $pkgparts ) { + my $p2 = popurl(2); + my $typenum = $agent->typenum; + my $agent_type = qsearchs( 'agent_type', { 'typenum' => $typenum } ); + my $atype = $agent_type->atype; + print <<END; +(No <a href="${p2}browse/part_pkg.cgi">package definitions</a>, or agent type +<a href="${p2}edit/agent_type.cgi?$typenum">$atype</a> not allowed to purchase +any packages.) +END +} + +#submit +print <<END; +<P><INPUT TYPE="submit" VALUE="Order"> + </FORM> + </BODY> +</HTML> +END +%> diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi new file mode 100755 index 000000000..8955c7cee --- /dev/null +++ b/httemplate/edit/cust_refund.cgi @@ -0,0 +1,94 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; +my $custnum = $cgi->param('custnum'); +my $refund = $cgi->param('refund'); +my $payby = $cgi->param('payby'); +my $reason = $cgi->param('reason'); + +my( $paynum, $cust_pay ) = ( '', '' ); +if ( $cgi->param('paynum') =~ /^(\d+)$/ ) { + $paynum = $1; + $cust_pay = qsearchs('cust_pay', { paynum=>$paynum } ) + or die "unknown payment # $paynum"; + $refund ||= $cust_pay->unrefunded; + if ( $custnum ) { + die "payment # $paynum is not for specified customer # $custnum" + unless $custnum == $cust_pay->custnum; + } else { + $custnum = $cust_pay->custnum; + } +} +die "no custnum or paynum specified!" unless $custnum; + +my $_date = time; + +my $p1 = popurl(1); + +print header('Refund '. ucfirst(lc($payby)). ' payment', ''); +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); +print <<END, small_custview($custnum, $conf->config('countrydefault')); + <FORM ACTION="${p1}process/cust_refund.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="refundnum" VALUE=""> + <INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum"> + <INPUT TYPE="hidden" NAME="paynum" VALUE="$paynum"> + <INPUT TYPE="hidden" NAME="_date" VALUE="$_date"> + <INPUT TYPE="hidden" NAME="payby" VALUE="$payby"> + <INPUT TYPE="hidden" NAME="payinfo" VALUE=""> + <INPUT TYPE="hidden" NAME="paybatch" VALUE=""> + <INPUT TYPE="hidden" NAME="credited" VALUE=""> + <BR> +END + +if ( $cust_pay ) { + + #false laziness w/FS/FS/cust_pay.pm + my $payby = $cust_pay->payby; + my $payinfo = $cust_pay->payinfo; + $payby =~ s/^BILL$/Check/ if $payinfo; + $payby =~ s/^CHEK$/Electronic check/; + $payinfo = $cust_pay->payinfo_masked if $payby eq 'CARD'; + + print '<BR>Payment'. ntable("#cccccc", 2). + '<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">$'. + $cust_pay->paid. '</TD></TR>'. + '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'. + time2str("%D",$cust_pay->_date). '</TD></TR>'. + '<TR><TD ALIGN="right">Method</TD><TD BGCOLOR="#ffffff">'. + ucfirst(lc($payby)). ' # '. $payinfo. '</TD></TR>'; + #false laziness w/FS/FS/cust_main::realtime_refund_bop + if ( $cust_pay->paybatch =~ /^(\w+):(\w+)(:(\w+))?$/ ) { + my ( $processor, $auth, $order_number ) = ( $1, $2, $4 ); + print '<TR><TD ALIGN="right">Processor</TD><TD BGCOLOR="#ffffff">'. + $processor. '</TD></TR>'; + print '<TR><TD ALIGN="right">Authorization</TD><TD BGCOLOR="#ffffff">'. + $auth. '</TD></TR>' + if length($auth); + print '<TR><TD ALIGN="right">Order number</TD><TD BGCOLOR="#ffffff">'. + $order_number. '</TD></TR>' + if length($order_number); + } + print '</TABLE>'; +} + +print '<BR>Refund'. ntable("#cccccc", 2). + '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'. + time2str("%D",$_date). '</TD></TR>'; + +print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="refund" VALUE="$refund" SIZE=8 MAXLENGTH=8></TD></TR>!; + +print qq!<TR><TD ALIGN="right">Reason</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="reason" VALUE="$reason"></TD></TR>!; + +print <<END; +</TABLE> +<BR> +<INPUT TYPE="submit" VALUE="Post refund"> + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/msgcat.cgi b/httemplate/edit/msgcat.cgi new file mode 100755 index 000000000..ee9b1c6b3 --- /dev/null +++ b/httemplate/edit/msgcat.cgi @@ -0,0 +1,58 @@ +<!-- mason kludge --> +<% + +print header("Edit Message catalog", menubar( +# 'Main Menu' => $p, +)), '<BR>'; + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !. $cgi->param('error'). + '</FONT><BR><BR>' + if $cgi->param('error'); + +my $widget = new HTML::Widgets::SelectLayers( + 'selected_layer' => 'en_US', + 'options' => { 'en_US'=>'en_US' }, + 'form_action' => 'process/msgcat.cgi', + 'layer_callback' => sub { + my $layer = shift; + my $html = qq!<INPUT TYPE="hidden" NAME="locale" VALUE="$layer">!. + "<BR>Messages for locale $layer<BR>". table(). + "<TR><TH COLSPAN=2>Code</TH>". + "<TH>Message</TH>"; + $html .= "<TH>en_US Message</TH>" unless $layer eq 'en_US'; + $html .= '</TR>'; + + #foreach my $msgcat ( sort { $a->msgcode cmp $b->msgcode } + # qsearch('msgcat', { 'locale' => $layer } ) ) { + foreach my $msgcat ( qsearch('msgcat', { 'locale' => $layer } ) ) { + $html .= + '<TR><TD>'. $msgcat->msgnum. '</TD><TD>'. $msgcat->msgcode. '</TD>'. + '<TD><INPUT TYPE="text" SIZE=32 '. + qq! NAME="!. $msgcat->msgnum. '" '. + qq!VALUE="!. ($cgi->param($msgcat->msgnum)||$msgcat->msg). qq!"></TD>!; + unless ( $layer eq 'en_US' ) { + my $en_msgcat = qsearchs('msgcat', { + 'locale' => 'en_US', + 'msgcode' => $msgcat->msgcode, + } ); + $html .= '<TD>'. $en_msgcat->msg. '</TD>'; + } + $html .= '</TR>'; + } + + $html .= '</TABLE><BR><INPUT TYPE="submit" VALUE="Apply changes">'; + + $html; + }, + +); + +print $widget->html; + +print <<END; + </TABLE> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi new file mode 100755 index 000000000..2f99ca58f --- /dev/null +++ b/httemplate/edit/part_bill_event.cgi @@ -0,0 +1,288 @@ +<!-- mason kludge --> +<% + +if ( $cgi->param('eventpart') && $cgi->param('eventpart') =~ /^(\d+)$/ ) { + $cgi->param('eventpart', $1); +} else { + $cgi->param('eventpart', ''); +} + +my ($query) = $cgi->keywords; +my $action = ''; +my $part_bill_event = ''; +if ( $cgi->param('error') ) { + $part_bill_event = new FS::part_bill_event ( { + map { $_, scalar($cgi->param($_)) } fields('part_bill_event') + } ); +} +if ( $query && $query =~ /^(\d+)$/ ) { + $part_bill_event ||= qsearchs('part_bill_event',{'eventpart'=>$1}); +} else { + $part_bill_event ||= new FS::part_bill_event {}; +} +$action ||= $part_bill_event->eventpart ? 'Edit' : 'Add'; +my $hashref = $part_bill_event->hashref; + +print header("$action Invoice Event Definition", menubar( + 'Main Menu' => popurl(2), + 'View all invoice events' => popurl(2). 'browse/part_bill_event.cgi', +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print '<FORM ACTION="', popurl(1), 'process/part_bill_event.cgi" METHOD=POST>'. + '<INPUT TYPE="hidden" NAME="eventpart" VALUE="'. + $part_bill_event->eventpart .'">'; +print "Invoice Event #", $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)"; + +print ntable("#cccccc",2), <<END; +<TR><TD ALIGN="right">Payby</TD><TD><SELECT NAME="payby"> +END + +for (qw(CARD DCRD CHEK DCHK LECB BILL COMP)) { + print qq!<OPTION VALUE="$_"!; + if ($part_bill_event->payby eq $_) { + print " SELECTED>$_</OPTION>"; + } else { + print ">$_</OPTION>"; + } +} + +my $days = $hashref->{seconds}/86400; + +print <<END; +</SELECT></TD></TR> +<TR><TD ALIGN="right">Event</TD><TD><INPUT TYPE="text" NAME="event" VALUE="$hashref->{event}"></TD></TR> +<TR><TD ALIGN="right">After</TD><TD><INPUT TYPE="text" NAME="days" VALUE="$days"> days</TD></TR> +END + +print '<TR><TD ALIGN="right">Disabled</TD><TD>'; +print '<INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"'; +print ' CHECKED' if $hashref->{disabled} eq "Y"; +print '>'; +print '</TD></TR>'; + +print '<TR><TD ALIGN="right">Action</TD><TD>'; + +#print ntable(); + +sub select_pkgpart { + my $label = shift; + my $plandata = shift; + my %selected = map { $_=>1 } split(/,\s*/, $plandata->{$label}); + qq(<SELECT NAME="$label" MULTIPLE>). + join("\n", map { + '<OPTION VALUE="'. $_->pkgpart. '"'. + ( $selected{$_->pkgpart} ? ' SELECTED' : '' ). + '>'. $_->pkg. ' - '. $_->comment + } qsearch('part_pkg', { 'disabled' => '' } ) ). + '</SELECT>'; +} + +sub select_agentnum { + my $plandata = shift; + my $agentnum = $plandata->{'agentnum'}; + '<SELECT NAME="agentnum">'. + join("\n", map { + '<OPTION VALUE="'. $_->agentnum. '"'. + ( $_->agentnum == $agentnum ? ' SELECTED' : '' ). + '>'. $_->agent + } qsearch('agent', { 'disabled' => '' } ) ). + '</SELECT>'; +} + +#this is pretty kludgy right here. +tie my %events, 'Tie::IxHash', + + 'fee' => { + 'name' => 'Late fee', + 'code' => '$cust_main->charge( %%%charge%%%, \'%%%reason%%%\' );', + 'html' => + 'Amount <INPUT TYPE="text" SIZE="7" NAME="charge" VALUE="%%%charge%%%">'. + '<BR>Reason <INPUT TYPE="text" NAME="reason" VALUE="%%%reason%%%">', + 'weight' => 10, + }, + 'suspend' => { + 'name' => 'Suspend', + 'code' => '$cust_main->suspend();', + 'weight' => 10, + }, + 'suspend-if-pkgpart' => { + 'name' => 'Suspend packages', + 'code' => '$cust_main->suspend_if_pkgpart(%%%if_pkgpart%%%);', + 'html' => sub { &select_pkgpart('if_pkgpart', @_) }, + 'weight' => 10, + }, + 'suspend-unless-pkgpart' => { + 'name' => 'Suspend packages except', + 'code' => '$cust_main->suspend_unless_pkgpart(%%%unless_pkgpart%%%);', + 'html' => sub { &select_pkgpart('unless_pkgpart', @_) }, + 'weight' => 10, + }, + 'cancel' => { + 'name' => 'Cancel', + 'code' => '$cust_main->cancel();', + 'weight' => 10, + }, + + 'addpost' => { + 'name' => 'Add postal invoicing', + 'code' => '$cust_main->invoicing_list_addpost(); "";', + 'weight' => 20, + }, + + 'comp' => { + 'name' => 'Pay invoice with a complimentary "payment"', + 'code' => '$cust_bill->comp();', + 'weight' => 30, + }, + + 'realtime-card' => { + 'name' => 'Run card with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', + 'code' => '$cust_bill->realtime_card();', + 'weight' => 30, + }, + + 'realtime-check' => { + 'name' => 'Run check with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', + 'code' => '$cust_bill->realtime_ach();', + 'weight' => 30, + }, + + 'realtime-lec' => { + 'name' => 'Run phone bill ("LEC") billing with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway', + 'code' => '$cust_bill->realtime_lec();', + 'weight' => 30, + }, + + 'batch-card' => { + 'name' => 'Add card to the pending credit card batch', + 'code' => '$cust_bill->batch_card();', + 'weight' => 40, + }, + + 'send' => { + 'name' => 'Send invoice (email/print)', + 'code' => '$cust_bill->send();', + 'weight' => 50, + }, + + 'send_alternate' => { + 'name' => 'Send invoice (email/print) with alternate template', + 'code' => '$cust_bill->send(\'%%%templatename%%%\');', + 'html' => + '<INPUT TYPE="text" NAME="templatename" VALUE="%%%templatename%%%">', + 'weight' => 50, + }, + + 'send_agent' => { + 'name' => 'Send invoice (email/print) ', + 'code' => '$cust_bill->send(\'%%%agent_templatename%%%\', %%%agentnum%%%, \'%%%agent_invoice_from%%%\');', + 'html' => sub { + '<TABLE BORDER=0> + <TR> + <TD ALIGN="right">only for agent </TD> + <TD>'. &select_agentnum(@_). '</TD> + </TR> + <TR> + <TD ALIGN="right">with template </TD> + <TD> + <INPUT TYPE="text" NAME="agent_templatename" VALUE="%%%agent_templatename%%%"> + </TD> + </TR> + <TR> + <TD ALIGN="right">email From: </TD> + <TD> + <INPUT TYPE="text" NAME="agent_invoice_from" VALUE="%%%agent_invoice_from%%%"> + </TD> + </TR> + </TABLE>'; + }, + 'weight' => 50, + }, + + 'send_csv_ftp' => { + 'name' => 'Upload CSV invoice data to an FTP server', + 'code' => '$cust_bill->send_csv( protocol => \'ftp\', + server => \'%%%ftpserver%%%\', + username => \'%%%ftpusername%%%\', + password => \'%%%ftppassword%%%\', + dir => \'%%%ftpdir%%%\' );', + 'html' => + '<TABLE BORDER=0><TR><TD ALIGN="right">FTP server: </TD>'. + '<TD><INPUT TYPE="text" NAME="ftpserver" VALUE="%%%ftpserver%%%">'. + '</TD></TR>'. + '<TR><TD ALIGN="right">FTP username: </TD><TD>'. + '<INPUT TYPE="text" NAME="ftpusername" VALUE="%%%ftpusername%%%">'. + '</TD></TR>'. + '<TR><TD ALIGN="right">FTP password: </TD><TD>'. + '<INPUT TYPE="text" NAME="ftppassword" VALUE="%%%ftppassword%%%">'. + '</TD></TR>'. + '<TR><TD ALIGN="right">FTP directory: </TD>'. + '<TD><INPUT TYPE="text" NAME="ftpdir" VALUE="%%%ftpdir%%%">'. + '</TD></TR>'. + '</TABLE>', + 'weight' => 50, + }, + + 'bill' => { + 'name' => 'Generate invoices (normally only used with a <i>Late Fee</i> event)', + 'code' => '$cust_main->bill();', + 'weight' => 60, + }, + + 'apply' => { + 'name' => 'Apply unapplied payments and credits', + 'code' => '$cust_main->apply_payments; $cust_main->apply_credits; "";', + 'weight' => 70, + }, + + 'collect' => { + 'name' => 'Collect on invoices (normally only used with a <i>Late Fee</i> and <i>Generate Invoice</i> events)', + 'code' => '$cust_main->collect();', + 'weight' => 80, + }, + +; + +foreach my $event ( keys %events ) { + my %plandata = map { /^(\w+) (.*)$/; ($1, $2); } + split(/\n/, $part_bill_event->plandata); + my $html = $events{$event}{html}; + if ( ref($html) eq 'CODE' ) { + $html = &{$html}(\%plandata); + } + while ( $html =~ /%%%(\w+)%%%/ ) { + my $field = $1; + $html =~ s/%%%$field%%%/$plandata{$field}/; + } + + print ntable( "#cccccc", 2). + qq!<TR><TD><INPUT TYPE="radio" NAME="plan_weight_eventcode" !; + print "CHECKED " if $event eq $part_bill_event->plan; + print qq!VALUE="!. $event. ":". $events{$event}{weight}. ":". + encode_entities($events{$event}{code}). + qq!">$events{$event}{name}</TD>!; + print '<TD>'. $html. '</TD>' if $html; + print qq!</TR>!; + print '</TABLE>'; +} + +#print '</TABLE>'; + +print <<END; +</TD></TR> +</TABLE> +END + +print qq!<INPUT TYPE="submit" VALUE="!, + $hashref->{eventpart} ? "Apply changes" : "Add invoice event", + qq!">!; +%> + + </FORM> + </BODY> +</HTML> + diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi new file mode 100644 index 000000000..b3d42bd96 --- /dev/null +++ b/httemplate/edit/part_export.cgi @@ -0,0 +1,128 @@ +<!-- mason kludge --> +<% + +#if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) { +# $cgi->param('clone', $1); +#} else { +# $cgi->param('clone', ''); +#} + +my($query) = $cgi->keywords; +my $action = ''; +my $part_export = ''; +if ( $cgi->param('error') ) { + $part_export = new FS::part_export ( { + map { $_, scalar($cgi->param($_)) } fields('part_export') + } ); +} elsif ( $query =~ /^(\d+)$/ ) { + $part_export = qsearchs('part_export', { 'exportnum' => $1 } ); +} else { + $part_export = new FS::part_export; +} +$action ||= $part_export->exportnum ? 'Edit' : 'Add'; + +#my $exports = FS::part_export::export_info($svcdb); +my $exports = FS::part_export::export_info(); + +my %layers = map { $_ => "$_ - ". $exports->{$_}{desc} } keys %$exports; +$layers{''}=''; + +my $widget = new HTML::Widgets::SelectLayers( + 'selected_layer' => $part_export->exporttype, + 'options' => \%layers, + 'form_name' => 'dummy', + 'form_action' => 'process/part_export.cgi', + 'form_text' => [qw( exportnum machine )], +# 'form_checkbox' => [qw()], + 'html_between' => "</TD></TR></TABLE>\n", + 'layer_callback' => sub { + my $layer = shift; + my $html = qq!<INPUT TYPE="hidden" NAME="exporttype" VALUE="$layer">!. + ntable("#cccccc",2); + + $html .= '<TR><TD ALIGN="right">Description</TD><TD BGCOLOR=#ffffff>'. + $exports->{$layer}{notes}. '</TD></TR>' + if $layer; + + foreach my $option ( keys %{$exports->{$layer}{options}} ) { + my $optinfo = $exports->{$layer}{options}{$option}; + die "Retreived non-ref export info option from $layer export: $optinfo" + unless ref($optinfo); + my $label = $optinfo->{label}; + my $type = defined($optinfo->{type}) ? $optinfo->{type} : 'text'; + my $value = $cgi->param($option) + || ( $part_export->exportnum && $part_export->option($option) ) + || ( (exists $optinfo->{default} && !$part_export->exportnum) + ? $optinfo->{default} + : '' + ); + $html .= qq!<TR><TD ALIGN="right">$label</TD><TD>!; + if ( $type eq 'select' ) { + $html .= qq!<SELECT NAME="$option">!; + foreach my $select_option ( @{$optinfo->{options}} ) { + #if ( ref($select_option) ) { + #} else { + my $selected = $select_option eq $value ? ' SELECTED' : ''; + $html .= qq!<OPTION VALUE="$select_option"$selected>!. + qq!$select_option</OPTION>!; + #} + } + $html .= '</SELECT>'; + } elsif ( $type eq 'textarea' ) { + $html .= qq!<TEXTAREA NAME="$option" COLS=80 ROWS=8 WRAP="virtual">!. + encode_entities($value). '</TEXTAREA>'; + } elsif ( $type eq 'text' ) { + $html .= qq!<INPUT TYPE="text" NAME="$option" VALUE="!. + encode_entities($value). '" SIZE=64>'; + } elsif ( $type eq 'checkbox' ) { + $html .= qq!<INPUT TYPE="checkbox" NAME="$option" VALUE="1"!; + $html .= ' CHECKED' if $value; + $html .= '>'; + } else { + $html .= "unknown type $type"; + } + $html .= '</TD></TR>'; + } + $html .= '</TABLE>'; + + $html .= '<INPUT TYPE="hidden" NAME="options" VALUE="'. + join(',', keys %{$exports->{$layer}{options}} ). '">'; + + $html .= '<INPUT TYPE="hidden" NAME="nodomain" VALUE="'. + $exports->{$layer}{nodomain}. '">'; + + $html .= '<INPUT TYPE="submit" VALUE="'. + ( $part_export->exportnum ? "Apply changes" : "Add export" ). + '">'; + + $html; + }, +); + +%> +<%= header("$action Export", menubar( + 'Main Menu' => popurl(2), +), ' onLoad="visualize()"') +%> + +<% if ( $cgi->param('error') ) { %> + <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT> + <BR><BR> +<% } %> + +<FORM NAME="dummy"> +<INPUT TYPE="hidden" NAME="exportnum" VALUE="<%= $part_export->exportnum %>"> + +<%= ntable("#cccccc",2) %> +<TR> + <TD ALIGN="right">Export host</TD> + <TD> + <INPUT TYPE="text" NAME="machine" VALUE="<%= $part_export->machine %>"> + </TD> +</TR> +<TR> + <TD ALIGN="right">Export</TD> + <TD><%= $widget->html %> +</BODY> +</HTML> + diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi new file mode 100755 index 000000000..b3c389c9d --- /dev/null +++ b/httemplate/edit/part_pkg.cgi @@ -0,0 +1,345 @@ +<!-- mason kludge --> +<% + +if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) { + $cgi->param('clone', $1); +} else { + $cgi->param('clone', ''); +} +if ( $cgi->param('pkgnum') && $cgi->param('pkgnum') =~ /^(\d+)$/ ) { + $cgi->param('pkgnum', $1); +} else { + $cgi->param('pkgnum', ''); +} + +my ($query) = $cgi->keywords; +my $action = ''; +my $part_pkg = ''; +if ( $cgi->param('error') ) { + $part_pkg = new FS::part_pkg ( { + map { $_, scalar($cgi->param($_)) } fields('part_pkg') + } ); +} +my $clone_part_pkg = ''; +if ( $cgi->param('clone') ) { + $action = 'Custom Pricing'; + $clone_part_pkg= qsearchs('part_pkg', { 'pkgpart' => $cgi->param('clone') } ); + $part_pkg ||= $clone_part_pkg->clone; + $part_pkg->disabled('Y'); +} elsif ( $query && $query =~ /^(\d+)$/ ) { + $part_pkg ||= qsearchs('part_pkg',{'pkgpart'=>$1}); +} else { + unless ( $part_pkg ) { + $part_pkg = new FS::part_pkg {}; + $part_pkg->plan('flat'); + } +} +unless ( $part_pkg->plan ) { #backwards-compat + $part_pkg->plan('flat'); + $part_pkg->plandata("setup_fee=". $part_pkg->setup. "\n". + "recur_fee=". $part_pkg->recur. "\n"); +} +$action ||= $part_pkg->pkgpart ? 'Edit' : 'Add'; +my $hashref = $part_pkg->hashref; + +%> + +<%= header("$action Package Definition", menubar( + 'Main Menu' => popurl(2), + 'View all packages' => popurl(2). 'browse/part_pkg.cgi', +)) %> + +<% #), ' onLoad="visualize()"'); %> + +<% if ( $cgi->param('error') ) { %> + <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT> +<% } %> + +<% #print '<FORM ACTION="', popurl(1), 'process/part_pkg.cgi" METHOD=POST>'; %> + +<FORM NAME="dummy"> + +<% +#if ( $cgi->param('clone') ) { +# print qq!<INPUT TYPE="hidden" NAME="clone" VALUE="!, $cgi->param('clone'), qq!">!; +#} +#if ( $cgi->param('pkgnum') ) { +# print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="!, $cgi->param('pkgnum'), qq!">!; +#} +# +#print qq!<INPUT TYPE="hidden" NAME="pkgpart" VALUE="$hashref->{pkgpart}">!, +%> + +<%= itable('',8,1) %><TR><TD VALIGN="top"> + +Package information + +<%= ntable("#cccccc",2) %> + <TR> + <TD ALIGN="right">Package Definition #</TD> + <TD BGCOLOR="#ffffff"> + <%= $hashref->{pkgpart} ? $hashref->{pkgpart} : "(NEW)" %> + </TD> + </TR> + <TR> + <TD ALIGN="right">Package (customer-visible)</TD> + <TD> + <INPUT TYPE="text" NAME="pkg" SIZE=32 VALUE="<%= $part_pkg->pkg %>"> + </TD> + </TR> + <TR> + <TD ALIGN="right">Comment (customer-hidden)</TD> + <TD> + <INPUT TYPE="text" NAME="comment" SIZE=32 VALUE="<%=$part_pkg->comment%>"> + </TD> + </TR> + <TR> + <TD ALIGN="right">Promotional code</TD> + <TD> + <INPUT TYPE="text" NAME="promo_code" SIZE=32 VALUE="<%=$part_pkg->promo_code%>"> + </TD> + </TR> + <TR> + <TD ALIGN="right">Disable new orders</TD> + <TD> + <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %> + </TD> + </TR> + +</TABLE> + +</TD><TD VALIGN="top"> + +Tax information +<%= ntable("#cccccc", 2) %> + <TR> + <TD ALIGN="right">Setup fee tax exempt</TD> + <TD> +<% + +print '<INPUT TYPE="checkbox" NAME="setuptax" VALUE="Y"'; +print ' CHECKED' if $hashref->{setuptax} eq "Y"; +print '>'; + +print <<END; +</TD></TR> +<TR><TD ALIGN="right">Recurring fee tax exempt</TD><TD> +END + +print '<INPUT TYPE="checkbox" NAME="recurtax" VALUE="Y"'; +print ' CHECKED' if $hashref->{recurtax} eq "Y"; +print '>'; + +print '</TD></TR>'; + +my $conf = new FS::Conf; +#false laziness w/ view/cust_main.cgi quick order +if ( $conf->exists('enable_taxclasses') ) { + print '<TR><TD ALIGN="right">Tax class</TD><TD><SELECT NAME="taxclass">'; + my $sth = dbh->prepare('SELECT DISTINCT taxclass FROM cust_main_county') + or die dbh->errstr; + $sth->execute or die $sth->errstr; + foreach my $taxclass ( map $_->[0], @{$sth->fetchall_arrayref} ) { + print qq!<OPTION VALUE="$taxclass"!; + print ' SELECTED' if $taxclass eq $hashref->{taxclass}; + print qq!>$taxclass</OPTION>!; + } + print '</SELECT></TD></TR>'; +} else { + print + '<INPUT TYPE="hidden" NAME="taxclass" VALUE="'. $hashref->{taxclass}. '">'; +} + +%> + +</TABLE> + +</TD></TR></TABLE> + +<% + +my $thead = "\n\n". ntable('#cccccc', 2). + '<TR><TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Quan.</FONT></TH>'; +$thead .= '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Primary</FONT></TH>' + if dbdef->table('pkg_svc')->column('primary_svc'); +$thead .= '<TH BGCOLOR="#dcdcdc">Service</TH></TR>'; + +#unless ( $cgi->param('clone') ) { +#dunno why... +unless ( 0 ) { + #print <<END, $thead; + print <<END, itable('', 4, 1), '<TR><TD VALIGN="top">', $thead; +<BR><BR>Services included +END +} + +my @fixups = (); +my $count = 0; +my $columns = 3; +my @part_svc = qsearch( 'part_svc', { 'disabled' => '' } ); +foreach my $part_svc ( @part_svc ) { + my $svcpart = $part_svc->svcpart; + my $pkgpart = $cgi->param('clone') || $part_pkg->pkgpart; + my $pkg_svc = $pkgpart && qsearchs( 'pkg_svc', { + 'pkgpart' => $pkgpart, + 'svcpart' => $svcpart, + } ) || new FS::pkg_svc ( { + 'pkgpart' => $pkgpart, + 'svcpart' => $svcpart, + 'quantity' => 0, + 'primary_svc' => '', + }); + #? #next unless $pkg_svc; + + push @fixups, "pkg_svc$svcpart"; + + #unless ( defined ($cgi->param('clone')) && $cgi->param('clone') ) { + #dunno why... + unless ( 0 ) { + print '<TR>'; # if $count == 0 ; + print qq!<TD><INPUT TYPE="text" NAME="pkg_svc$svcpart" SIZE=4 MAXLENGTH=3 VALUE="!, + $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0, + qq!"></TD>!; + if ( dbdef->table('pkg_svc')->column('primary_svc') ) { + print qq!<TD><INPUT TYPE="radio" NAME="pkg_svc_primary" VALUE="$svcpart"!; + print ' CHECKED' if $pkg_svc->primary_svc =~ /^Y/i; + print '></TD>'; + } + print qq!<TD><A HREF="part_svc.cgi?!,$part_svc->svcpart, + qq!">!, $part_svc->getfield('svc'), "</A></TD></TR>"; +# print "</TABLE></TD><TD>$thead" if ++$count == int(scalar(@part_svc) / 2); + $count+=1; + foreach ( 1 .. $columns-1 ) { + print "</TABLE></TD><TD VALIGN=\"top\">$thead" + if $count == int( $_ * scalar(@part_svc) / $columns ); + } + } else { + print qq!<INPUT TYPE="hidden" NAME="pkg_svc$svcpart" VALUE="!, + $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0, qq!">\n!; + } +} + +#unless ( $cgi->param('clone') ) { +#dunno why... +unless ( 0 ) { + print "</TR></TABLE></TD></TR></TABLE>"; + #print "</TR></TABLE>"; +} + +foreach my $f ( qw( clone pkgnum ) ) { + print qq!<INPUT TYPE="hidden" NAME="$f" VALUE="!. $cgi->param($f). '">'; +} +print '<INPUT TYPE="hidden" NAME="pkgpart" VALUE="'. $part_pkg->pkgpart. '">'; + +# prolly should be in database +tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() }; + +my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } + split("\n", ($clone_part_pkg||$part_pkg)->plandata ); +#warn join("\n", map { "$_: $plandata{$_}" } keys %plandata ). "\n"; + +tie my %options, 'Tie::IxHash', map { $_=>$plans{$_}->{'name'} } keys %plans; + +my @form_select = (); +if ( $conf->exists('enable_taxclasses') ) { + push @form_select, 'taxclass'; +} else { + push @fixups, 'taxclass'; #hidden +} + +my @form_radio = (); +if ( dbdef->table('pkg_svc')->column('primary_svc') ) { + push @form_radio, 'pkg_svc_primary'; +} + +tie my %freq, 'Tie::IxHash', %FS::part_pkg::freq; +if ( $part_pkg->dbdef_table->column('freq')->type =~ /(int)/i ) { + delete $freq{$_} foreach grep { ! /^\d+$/ } keys %freq; +} + +my $widget = new HTML::Widgets::SelectLayers( + 'selected_layer' => $part_pkg->plan, + 'options' => \%options, + 'form_name' => 'dummy', + 'form_action' => 'process/part_pkg.cgi', + 'form_text' => [ qw(pkg comment promo_code clone pkgnum pkgpart), + @fixups + ], + 'form_checkbox' => [ qw(setuptax recurtax disabled) ], + 'form_radio' => \@form_radio, + 'form_select' => \@form_select, + 'layer_callback' => sub { + my $layer = shift; + my $html = qq!<INPUT TYPE="hidden" NAME="plan" VALUE="$layer">!. + ntable("#cccccc",2); + $html .= ' + <TR> + <TD ALIGN="right">Recurring fee frequency </TD> + <TD><SELECT NAME="freq"> + '; + + my @freq = keys %freq; + @freq = grep { /^\d+$/ } @freq + if exists($plans{$layer}->{'freq'}) && $plans{$layer}->{'freq'} eq 'm'; + foreach my $freq ( @freq ) { + $html .= qq(<OPTION VALUE="$freq"); + $html .= ' SELECTED' if $freq eq $part_pkg->freq; + $html .= ">$freq{$freq}"; + } + $html .= '</SELECT></TD></TR>'; + + my $href = $plans{$layer}->{'fields'}; + foreach my $field ( exists($plans{$layer}->{'fieldorder'}) + ? @{$plans{$layer}->{'fieldorder'}} + : keys %{ $href } + ) { + + $html .= '<TR><TD ALIGN="right">'. $href->{$field}{'name'}. '</TD><TD>'; + + if ( ! exists($href->{$field}{'type'}) ) { + $html .= qq!<INPUT TYPE="text" NAME="$field" VALUE="!. + ( exists($plandata{$field}) + ? $plandata{$field} + : $href->{$field}{'default'} ). + qq!" onChange="fchanged(this)">!; + } elsif ( $href->{$field}{'type'} =~ /^select/ ) { + $html .= '<SELECT'; + $html .= ' MULTIPLE' + if $href->{$field}{'type'} eq 'select_multiple'; + $html .= qq! NAME="$field" onChange="fchanged(this)">!; + foreach my $record ( + qsearch( $href->{$field}{'select_table'}, + $href->{$field}{'select_hash'} ) + ) { + my $value = $record->getfield($href->{$field}{'select_key'}); + $html .= qq!<OPTION VALUE="$value"!. + ( $plandata{$field} =~ /(^|, *)$value *(,|$)/ + ? ' SELECTED' + : '' ). + '>'. $record->getfield($href->{$field}{'select_label'}) + } + $html .= '</SELECT>'; + } + + $html .= '</TD></TR>'; + } + $html .= '</TABLE>'; + + $html .= '<INPUT TYPE="hidden" NAME="plandata" VALUE="'. + join(',', keys %{ $href } ). '">'. + '<BR><BR>'; + + $html .= '<INPUT TYPE="submit" VALUE="'. + ( $hashref->{pkgpart} ? "Apply changes" : "Add package" ). + '" onClick="fchanged(this)">'; + + $html; + + }, +); + +%> + +<BR><BR>Price plan <%= $widget->html %> + </BODY> +</HTML> diff --git a/httemplate/edit/part_referral.cgi b/httemplate/edit/part_referral.cgi new file mode 100755 index 000000000..f784dfa3e --- /dev/null +++ b/httemplate/edit/part_referral.cgi @@ -0,0 +1,48 @@ +<!-- mason kludge --> +<% + +my $part_referral; +if ( $cgi->param('error') ) { + $part_referral = new FS::part_referral ( { + map { $_, scalar($cgi->param($_)) } fields('part_referral') + } ); +} elsif ( $cgi->keywords ) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $part_referral = qsearchs( 'part_referral', { 'refnum' => $1 } ); +} else { #adding + $part_referral = new FS::part_referral {}; +} +my $action = $part_referral->refnum ? 'Edit' : 'Add'; +my $hashref = $part_referral->hashref; + +my $p1 = popurl(1); +print header("$action Advertising source", menubar( + 'Main Menu' => popurl(2), + 'View all advertising sources' => popurl(2). "browse/part_referral.cgi", +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="${p1}process/part_referral.cgi" METHOD=POST>!; + +print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$hashref->{refnum}">!; +#print "Referral #", $hashref->{refnum} ? $hashref->{refnum} : "(NEW)"; + +print <<END; +Advertising source <INPUT TYPE="text" NAME="referral" SIZE=32 VALUE="$hashref->{referral}"> +END + +print qq!<BR><INPUT TYPE="submit" VALUE="!, + $hashref->{refnum} ? "Apply changes" : "Add advertising source", + qq!">!; + +print <<END; + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi new file mode 100755 index 000000000..befd9b24a --- /dev/null +++ b/httemplate/edit/part_svc.cgi @@ -0,0 +1,332 @@ +<% +my $part_svc; +my $clone = ''; +my $error = ''; +if ( $cgi->param('magic') eq 'process' ) { + + my $svcpart = $cgi->param('svcpart'); + my $old = qsearchs('part_svc', { 'svcpart' => $svcpart }) if $svcpart; + + $cgi->param( 'svc_acct__usergroup', + join(',', $cgi->param('svc_acct__usergroup') ) ); + + my $new = new FS::part_svc ( { + map { + $_, scalar($cgi->param($_)); + # } qw(svcpart svc svcdb) + } ( fields('part_svc'), + map { my $svcdb = $_; + my @fields = fields($svcdb); + push @fields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge + map { ( $svcdb.'__'.$_, $svcdb.'__'.$_.'_flag' ) } @fields; + } grep defined( $FS::Record::dbdef->table($_) ), + qw( svc_acct svc_domain svc_forward svc_www svc_broadband ) + ) + } ); + + my %exportnums = + map { $_->exportnum => ( $cgi->param('exportnum'.$_->exportnum) || '') } + qsearch('part_export', {} ); + + if ( $svcpart ) { + $error = $new->replace($old, '1.3-COMPAT', [ 'usergroup' ], \%exportnums ); + } else { + $error = $new->insert( [ 'usergroup' ], \%exportnums ); + $svcpart = $new->getfield('svcpart'); + } + + unless ( $error ) { #no error, redirect + #print $cgi->redirect(popurl(3)."browse/part_svc.cgi"); + print $cgi->redirect("${p}browse/part_svc.cgi"); + myexit; + } + + $part_svc = $new; #?? + #$part_svc = new FS::part_svc ( { + # map { $_, scalar($cgi->param($_)) } fields('part_svc') + #} ); + +} elsif ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone + #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query"; + $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } ) + or die "unknown svcpart: $1"; + $clone = $part_svc->svcpart; + $part_svc->svcpart(''); +} elsif ( $cgi->keywords ) { #edit + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/ or die "malformed query: $query"; + $part_svc=qsearchs('part_svc', { 'svcpart'=>$1 } ) + or die "unknown svcpart: $1"; +} else { #adding + $part_svc = new FS::part_svc {}; +} + +my $action = $part_svc->svcpart ? 'Edit' : 'Add'; +my $hashref = $part_svc->hashref; +# my $p_svcdb = $part_svc->svcdb || 'svc_acct'; + + + #" onLoad=\"visualize()\"" +%> +<!-- mason kludge --> +<%= header("$action Service Definition", + menubar( 'Main Menu' => $p, + 'View all service definitions' => "${p}browse/part_svc.cgi" + ), + ) +%> + +<% if ( $error ) { %> +<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $error %></FONT> +<% } %> + +<FORM NAME="dummy"> + + Service Part #<%= $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %> +<BR><BR> +Service <INPUT TYPE="text" NAME="svc" VALUE="<%= $hashref->{svc} %>"><BR> +Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR> +<INPUT TYPE="hidden" NAME="magic" VALUE="process"> +<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $hashref->{svcpart} %>"> +<BR> +Services are items you offer to your customers. +<UL><LI>svc_acct - Shell accounts, POP mailboxes, SLIP/PPP and ISDN accounts + <LI>svc_domain - Domains + <LI>svc_forward - mail forwarding + <LI>svc_www - Virtual domain website + <LI>svc_broadband - Broadband/High-speed Internet service + <LI>svc_external - Externally-tracked service +<!-- <LI>svc_charge - One-time charges (Partially unimplemented) + <LI>svc_wo - Work orders (Partially unimplemented) +--> +</UL> +For the selected table, you can give fields default or fixed (unchangable) +values. For example, a SLIP/PPP account may have a default (or perhaps fixed) +<B>slipip</B> of <B>0.0.0.0</B>, while a POP mailbox will probably have a fixed +blank <B>slipip</B> as well as a fixed shell something like <B>/bin/true</B> or +<B>/usr/bin/passwd</B>. +<BR><BR> + +<% + +my %vfields; + +#these might belong somewhere else for other user interfaces +#pry need to eventually create stuff that's shared amount UIs +my $conf = new FS::Conf; +my %defs = ( + 'svc_acct' => { + 'dir' => 'Home directory', + 'uid' => 'UID (set to fixed and blank for dial-only)', + 'slipip' => 'IP address (Set to fixed and blank to disable dialin, or, set a value to be exported to RADIUS Framed-IP-Address. Use the special value <code>0e0</code> [zero e zero] to enable export to RADIUS without a Framed-IP-Address.)', +# 'popnum' => qq!<A HREF="$p/browse/svc_acct_pop.cgi/">POP number</A>!, + 'popnum' => { + desc => 'Access number', + type => 'select', + select_table => 'svc_acct_pop', + select_key => 'popnum', + select_label => 'city', + }, + 'username' => { + desc => 'Username', + type => 'disabled', + }, + 'quota' => '', + '_password' => 'Password', + 'gid' => 'GID (when blank, defaults to UID)', + 'shell' => { + desc =>'Shell (all service definitions should have a default or fixed shell that is present in the <b>shells</b> configuration file)', + type =>'select', + select_list => [ $conf->config('shells') ], + }, + 'finger' => 'GECOS', + 'domsvc' => { + desc =>'svcnum from svc_domain', + type =>'select', + select_table => 'svc_domain', + select_key => 'svcnum', + select_label => 'domain', + }, + 'usergroup' => { + desc =>'ICRADIUS/FreeRADIUS groups', + type =>'radius_usergroup_selector', + }, + }, + 'svc_domain' => { + 'domain' => 'Domain', + }, + 'svc_forward' => { + 'srcsvc' => 'service from which mail is to be forwarded', + 'dstsvc' => 'service to which mail is to be forwarded', + 'dst' => 'someone@another.domain.com to use when dstsvc is 0', + }, +# 'svc_charge' => { +# 'amount' => 'amount', +# }, +# 'svc_wo' => { +# 'worker' => 'Worker', +# '_date' => 'Date', +# }, + 'svc_www' => { + #'recnum' => '', + #'usersvc' => '', + }, + 'svc_broadband' => { + 'speed_down' => 'Maximum download speed for this service in Kbps. 0 denotes unlimited.', + 'speed_up' => 'Maximum upload speed for this service in Kbps. 0 denotes unlimited.', + 'ip_addr' => 'IP address. Leave blank for automatic assignment.', + 'blocknum' => 'Address block.', + }, + 'svc_external' => { + #'id' => '', + #'title' => '', + }, +); + + foreach my $svcdb (grep dbdef->table($_), keys %defs ) { + my $self = "FS::$svcdb"->new; + $vfields{$svcdb} = {}; + foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them + my $pvf = $self->pvf($field); + my @list = $pvf->list; + if (scalar @list) { + $defs{$svcdb}->{$field} = { desc => $pvf->label, + type => 'select', + select_list => \@list }; + } else { + $defs{$svcdb}->{$field} = $pvf->label; + } #endif + $vfields{$svcdb}->{$field} = $pvf; + warn "\$vfields{$svcdb}->{$field} = $pvf"; + } #next $field + } #next $svcdb + + my @dbs = $hashref->{svcdb} + ? ( $hashref->{svcdb} ) + : qw( svc_acct svc_domain svc_forward svc_www svc_broadband svc_external ); + + tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs; + my $widget = new HTML::Widgets::SelectLayers( + #'selected_layer' => $p_svcdb, + 'selected_layer' => $hashref->{svcdb} || 'svc_acct', + 'options' => \%svcdb, + 'form_name' => 'dummy', + #'form_action' => 'process/part_svc.cgi', + 'form_action' => 'part_svc.cgi', #self + 'form_text' => [ qw( magic svc svcpart ) ], + 'form_checkbox' => [ 'disabled' ], + 'layer_callback' => sub { + my $layer = shift; + my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!; + + my $columns = 3; + my $count = 0; + my @part_export = + map { qsearch( 'part_export', {exporttype => $_ } ) } + keys %{FS::part_export::export_info($layer)}; + $html .= '<BR><BR>'. table(). + table(). "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>"; + foreach my $part_export ( @part_export ) { + $html .= '<TD><INPUT TYPE="checkbox"'. + ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" '; + $html .= 'CHECKED' + if ( $clone || $part_svc->svcpart ) #null svcpart search causing error + && qsearchs( 'export_svc', { + exportnum => $part_export->exportnum, + svcpart => $clone || $part_svc->svcpart }); + $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype. + ' to '. $part_export->machine. '</TD>'; + $count++; + $html .= '</TR><TR>' unless $count % $columns; + } + $html .= '</TR></TABLE><BR><BR>'; + + $html .= table(). "<TH>Field</TH><TH COLSPAN=2>Modifier</TH>"; + #yucky kludge + my @fields = defined( $FS::Record::dbdef->table($layer) ) + ? grep { $_ ne 'svcnum' } fields($layer) + : (); + push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge + $part_svc->svcpart($clone) if $clone; #haha, undone below + foreach my $field (@fields) { + my $part_svc_column = $part_svc->part_svc_column($field); + my $value = $error + ? $cgi->param("${layer}__${field}") + : $part_svc_column->columnvalue; + my $flag = $error + ? $cgi->param("${layer}__${field}_flag") + : $part_svc_column->columnflag; + my $def = $defs{$layer}{$field}; + my $desc = ref($def) ? $def->{desc} : $def; + + $html .= "<TR><TD>$field"; + $html .= "- <FONT SIZE=-1>$desc</FONT>" if $desc; + $html .= "</TD>"; + $flag = '' if ref($def) && $def->{type} eq 'disabled'; + $html .= + qq!<TD><INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE=""!. + ' CHECKED'x($flag eq ''). ">Off</TD>". + '<TD>'; + unless ( ref($def) && $def->{type} eq 'disabled' ) { + $html .= + qq!<INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="D"!. + ' CHECKED'x($flag eq 'D'). ">Default ". + qq!<INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="F"!. + ' CHECKED'x($flag eq 'F'). ">Fixed "; + $html .= '<BR>'; + } + if ( ref($def) ) { + if ( $def->{type} eq 'select' ) { + $html .= qq!<SELECT NAME="${layer}__${field}">!; + $html .= '<OPTION> </OPTION>' unless $value; + if ( $def->{select_table} ) { + foreach my $record ( qsearch( $def->{select_table}, {} ) ) { + my $rvalue = $record->getfield($def->{select_key}); + $html .= qq!<OPTION VALUE="$rvalue"!. + ( $rvalue==$value ? ' SELECTED>' : '>' ). + $record->getfield($def->{select_label}). '</OPTION>'; + } #next $record + } else { # select_list + foreach my $item ( @{$def->{select_list}} ) { + $html .= qq!<OPTION VALUE="$item"!. + ( $item eq $value ? ' SELECTED>' : '>' ). + $item. '</OPTION>'; + } #next $item + } #endif + $html .= '</SELECT>'; + } elsif ( $def->{type} eq 'radius_usergroup_selector' ) { + $html .= FS::svc_acct::radius_usergroup_selector( + [ split(',', $value) ], "${layer}__${field}" ); + } elsif ( $def->{type} eq 'disabled' ) { + $html .= + qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!; + } else { + $html .= '<font color="#ff0000">unknown type'. $def->{type}; + } + } else { + $html .= + qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value">!; + } + + if($vfields{$layer}->{$field}) { + $html .= qq!<BR><INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="X"!. + ' CHECKED'x($flag eq 'X'). ">Excluded "; + } + $html .= "</TD></TR>\n"; + } + $part_svc->svcpart('') if $clone; #undone + $html .= "</TABLE>"; + + $html .= '<BR><INPUT TYPE="submit" VALUE="'. + ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">'; + + $html; + + }, + ); + +%> +Table <%= $widget->html %> + </BODY> +</HTML> + diff --git a/httemplate/edit/part_virtual_field.cgi b/httemplate/edit/part_virtual_field.cgi new file mode 100644 index 000000000..fb10321e8 --- /dev/null +++ b/httemplate/edit/part_virtual_field.cgi @@ -0,0 +1,92 @@ +<!-- mason kludge --> +<% +my ($vfieldpart, $part_virtual_field); + +if ( $cgi->param('error') ) { + $part_virtual_field = new FS::part_virtual_field ( { + map { $_, scalar($cgi->param($_)) } fields('part_virtual_field')}); + $vfieldpart = $part_virtual_field->vfieldpart; +} else { + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $vfieldpart=$1; + $part_virtual_field=qsearchs('part_virtual_field', + {'vfieldpart' => $vfieldpart}) + or die "Unknown vfieldpart!"; + + } else { #adding + $part_virtual_field = new FS::part_virtual_field({}); + } +} +my $action = $part_virtual_field->vfieldpart ? 'Edit' : 'Add'; + +my $p1 = popurl(1); +print header("$action Virtual Field Definition", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); +%> +<FORM ACTION="<%=$p1%>process/generic.cgi" METHOD="POST"> + +<INPUT TYPE="hidden" NAME="table" VALUE="part_virtual_field"> +<INPUT TYPE="hidden" NAME="redirect_ok" + VALUE="<%=popurl(2)%>browse/part_virtual_field.cgi"> +<INPUT TYPE="hidden" NAME="vfieldpart" VALUE="<%= + $vfieldpart%>"> +Field #<B><%=$vfieldpart or "(NEW)"%></B><BR><BR> + +<%=ntable("#cccccc",2)%> + <TR> + <TD ALIGN="right">Name</TD> + <TD><INPUT TYPE="text" NAME="name" MAXLENGTH=15 VALUE="<%= + $part_virtual_field->name%>"></TD> + </TR> + <TR> + <TD ALIGN="right">Table</TD> + <TD><% if ($action eq 'Add') { %> + <SELECT SIZE=1 NAME="dbtable"><% + my $dbdef = dbdef; # ick + foreach my $dbtable (sort { $a cmp $b } $dbdef->tables) { + if ($dbtable !~ /^h_/ + and $dbdef->table($dbtable)->primary_key) { %> + <OPTION VALUE="<%=$dbtable%>"><%=$dbtable%></OPTION><% + } + } + %></SELECT><% + } else { # Edit + %><%=$part_virtual_field->dbtable%> + <INPUT TYPE="hidden" NAME="dbtable" VALUE="<%=$part_virtual_field->dbtable%>"> + <% } %> + </TD> + <TR> + <TD ALIGN="right">Label</TD> + <TD><INPUT TYPE="text" NAME="label" MAXLENGTH="20" VALUE="<%= + $part_virtual_field->label%>"></TD> + </TR> + <TR> + <TD ALIGN="right">Length</TD> + <TD><INPUT TYPE="text" NAME="length" MAXLENGTH=4 VALUE="<%= + $part_virtual_field->length%>"></TD> + </TR> + <TR> + <TD ALIGN="right">Check</TD> + <TD><TEXTAREA COLS="20" ROWS="4" NAME="check_block"><%= + $part_virtual_field->check_block%></TEXTAREA></TD> + </TR> + <TR> + <TD ALIGN="right">List source</TD> + <TD><TEXTAREA COLS="20" ROWS="4" NAME="list_source"><%= + $part_virtual_field->list_source%></TEXTAREA></TD> + </TR> +</TABLE><BR><INPUT TYPE="submit" VALUE="Submit"> + +</FORM> + +<BR><BR> +<FONT SIZE=-2>If you don't understand what <I>check_block</I> and +<I>list_source</I> mean, <B>LEAVE THEM BLANK</B>. We mean it.</FONT> + + +</BODY> +</HTML> diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi new file mode 100755 index 000000000..3d697ddfd --- /dev/null +++ b/httemplate/edit/process/REAL_cust_pkg.cgi @@ -0,0 +1,24 @@ +<% + +my $pkgnum = $cgi->param('pkgnum') or die; +my $old = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); +my %hash = $old->hash; +$hash{'setup'} = $cgi->param('setup') ? str2time($cgi->param('setup')) : ''; +$hash{'bill'} = $cgi->param('bill') ? str2time($cgi->param('bill')) : ''; +$hash{'last_bill'} = + $cgi->param('last_bill') ? str2time($cgi->param('last_bill')) : ''; +$hash{'expire'} = $cgi->param('expire') ? str2time($cgi->param('expire')) : ''; +my $new = new FS::cust_pkg \%hash; + +my $error = $new->replace($old); + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "REAL_cust_pkg.cgi?". $cgi->query_string ); +} else { + my $custnum = $new->custnum; + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum". + "#cust_pkg$pkgnum" ); +} + +%> diff --git a/httemplate/edit/process/addr_block/add.cgi b/httemplate/edit/process/addr_block/add.cgi new file mode 100755 index 000000000..34d799ccd --- /dev/null +++ b/httemplate/edit/process/addr_block/add.cgi @@ -0,0 +1,20 @@ +<% + +my $error = ''; +my $ip_gateway = $cgi->param('ip_gateway'); +my $ip_netmask = $cgi->param('ip_netmask'); + +my $new = new FS::addr_block { + ip_gateway => $ip_gateway, + ip_netmask => $ip_netmask, + routernum => 0 }; + +$error = $new->insert; + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(4). "browse/addr_block.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(4). "browse/addr_block.cgi"); +} +%> diff --git a/httemplate/edit/process/addr_block/allocate.cgi b/httemplate/edit/process/addr_block/allocate.cgi new file mode 100755 index 000000000..85b0d7a7a --- /dev/null +++ b/httemplate/edit/process/addr_block/allocate.cgi @@ -0,0 +1,25 @@ +<% +my $error = ''; +my $blocknum = $cgi->param('blocknum'); +my $routernum = $cgi->param('routernum'); + +my $addr_block = qsearchs('addr_block', { blocknum => $blocknum }); +my $router = qsearchs('router', { routernum => $routernum }); + +if($addr_block) { + if ($router) { + $error = $addr_block->allocate($router); + } else { + $error = "Cannot find router with routernum $routernum"; + } +} else { + $error = "Cannot find block with blocknum $blocknum"; +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(4). "browse/addr_block.cgi?" . $cgi->query_string); +} else { + print $cgi->redirect(popurl(4). "browse/addr_block.cgi"); +} +%> diff --git a/httemplate/edit/process/addr_block/deallocate.cgi b/httemplate/edit/process/addr_block/deallocate.cgi new file mode 100755 index 000000000..cfb7ed04d --- /dev/null +++ b/httemplate/edit/process/addr_block/deallocate.cgi @@ -0,0 +1,24 @@ +<% +my $error = ''; +my $blocknum = $cgi->param('blocknum'); + +my $addr_block = qsearchs('addr_block', { blocknum => $blocknum }); + +if($addr_block) { + my $router = $addr_block->router; + if ($router) { + $error = $addr_block->deallocate($router); + } else { + $error = "Block is not allocated to a router"; + } +} else { + $error = "Cannot find block with blocknum $blocknum"; +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(4). "browse/addr_block.cgi?" . $cgi->query_string); +} else { + print $cgi->redirect(popurl(4). "browse/addr_block.cgi"); +} +%> diff --git a/httemplate/edit/process/addr_block/split.cgi b/httemplate/edit/process/addr_block/split.cgi new file mode 100755 index 000000000..bb6d4ba3e --- /dev/null +++ b/httemplate/edit/process/addr_block/split.cgi @@ -0,0 +1,19 @@ +<% +my $error = ''; +my $blocknum = $cgi->param('blocknum'); +my $addr_block = qsearchs('addr_block', { blocknum => $blocknum }); + +if ( $addr_block) { + $error = $addr_block->split_block; +} else { + $error = "Unknown blocknum: $blocknum"; +} + + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(4). "browse/addr_block.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(4). "browse/addr_block.cgi"); +} +%> diff --git a/httemplate/edit/process/agent.cgi b/httemplate/edit/process/agent.cgi new file mode 100755 index 000000000..182eeab41 --- /dev/null +++ b/httemplate/edit/process/agent.cgi @@ -0,0 +1,28 @@ +<% + +my $agentnum = $cgi->param('agentnum'); + +my $old = qsearchs('agent',{'agentnum'=>$agentnum}) if $agentnum; + +my $new = new FS::agent ( { + map { + $_, scalar($cgi->param($_)); + } fields('agent') +} ); + +my $error; +if ( $agentnum ) { + $error=$new->replace($old); +} else { + $error=$new->insert; + $agentnum=$new->getfield('agentnum'); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/agent.cgi"); +} + +%> diff --git a/httemplate/edit/process/agent_type.cgi b/httemplate/edit/process/agent_type.cgi new file mode 100755 index 000000000..516594573 --- /dev/null +++ b/httemplate/edit/process/agent_type.cgi @@ -0,0 +1,55 @@ +<% + +my $typenum = $cgi->param('typenum'); +my $old = qsearchs('agent_type',{'typenum'=>$typenum}) if $typenum; + +my $new = new FS::agent_type ( { + map { + $_, scalar($cgi->param($_)); + } fields('agent_type') +} ); + +my $error; +if ( $typenum ) { + $error=$new->replace($old); +} else { + $error=$new->insert; + $typenum=$new->getfield('typenum'); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "agent_type.cgi?". $cgi->query_string ); +} else { + + #false laziness w/ edit/process/part_svc.cgi + foreach my $part_pkg (qsearch('part_pkg',{})) { + my($pkgpart)=$part_pkg->getfield('pkgpart'); + + my($type_pkgs)=qsearchs('type_pkgs',{ + 'typenum' => $typenum, + 'pkgpart' => $pkgpart, + }); + if ( $type_pkgs && ! $cgi->param("pkgpart$pkgpart") ) { + my($d_type_pkgs)=$type_pkgs; #need to save $type_pkgs for below. + $error=$d_type_pkgs->delete; + die $error if $error; + + } elsif ( $cgi->param("pkgpart$pkgpart") + && ! $type_pkgs + ) { + #ok to clobber it now (but bad form nonetheless?) + $type_pkgs=new FS::type_pkgs ({ + 'typenum' => $typenum, + 'pkgpart' => $pkgpart, + }); + $error= $type_pkgs->insert; + die $error if $error; + } + + } + + print $cgi->redirect(popurl(3). "browse/agent_type.cgi"); +} + +%> diff --git a/httemplate/edit/process/cust_bill_pay.cgi b/httemplate/edit/process/cust_bill_pay.cgi new file mode 100755 index 000000000..0025b16b5 --- /dev/null +++ b/httemplate/edit/process/cust_bill_pay.cgi @@ -0,0 +1,43 @@ +<% + +$cgi->param('paynum') =~ /^(\d*)$/ or die "Illegal paynum!"; +my $paynum = $1; + +my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ) + or die "No such paynum"; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_pay->custnum } ) + or die "Bogus credit: not attached to customer"; + +my $custnum = $cust_main->custnum; + +my $new; +if ($cgi->param('invnum') =~ /^Refund$/) { + $new = new FS::cust_refund ( { + 'reason' => 'Refunding payment', #enter reason in UI + 'refund' => $cgi->param('amount'), + 'payby' => 'BILL', + #'_date' => $cgi->param('_date'), + 'payinfo' => 'Cash', #enter payinfo in UI + 'paynum' => $paynum, + } ); +} else { + $new = new FS::cust_bill_pay ( { + map { + $_, scalar($cgi->param($_)); + #} qw(custnum _date amount invnum) + } fields('cust_bill_pay') + } ); +} + +my $error = $new->insert; + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_bill_pay.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} + + +%> diff --git a/httemplate/edit/process/cust_credit.cgi b/httemplate/edit/process/cust_credit.cgi new file mode 100755 index 000000000..85bfd4489 --- /dev/null +++ b/httemplate/edit/process/cust_credit.cgi @@ -0,0 +1,26 @@ +<% + +$cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!"; +my $custnum = $1; + +my $new = new FS::cust_credit ( { + map { + $_, scalar($cgi->param($_)); + } fields('cust_credit') +} ); + +my $error = $new->insert; + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_credit.cgi?". $cgi->query_string ); +} else { + if ( $cgi->param('apply') eq 'yes' ) { + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum }) + or die "unknown custnum $custnum"; + $cust_main->apply_credits; + } + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} + +%> diff --git a/httemplate/edit/process/cust_credit_bill.cgi b/httemplate/edit/process/cust_credit_bill.cgi new file mode 100755 index 000000000..23e2e6ce5 --- /dev/null +++ b/httemplate/edit/process/cust_credit_bill.cgi @@ -0,0 +1,43 @@ +<% + +$cgi->param('crednum') =~ /^(\d*)$/ or die "Illegal crednum!"; +my $crednum = $1; + +my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } ) + or die "No such crednum"; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_credit->custnum } ) + or die "Bogus credit: not attached to customer"; + +my $custnum = $cust_main->custnum; + +my $new; +if ($cgi->param('invnum') =~ /^Refund$/) { + $new = new FS::cust_refund ( { + 'reason' => $cust_credit->reason, + 'refund' => $cgi->param('amount'), + 'payby' => 'BILL', + #'_date' => $cgi->param('_date'), + 'payinfo' => 'Cash', + 'crednum' => $crednum, + } ); +} else { + $new = new FS::cust_credit_bill ( { + map { + $_, scalar($cgi->param($_)); + #} qw(custnum _date amount invnum) + } fields('cust_credit_bill') + } ); +} + +my $error = $new->insert; + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_credit_bill.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} + + +%> diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi new file mode 100755 index 000000000..a1d36986d --- /dev/null +++ b/httemplate/edit/process/cust_main.cgi @@ -0,0 +1,131 @@ +<% + +my $error = ''; + +#unmunge stuff + +$cgi->param('tax','') unless defined $cgi->param('tax'); + +$cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); + +my $payby = $cgi->param('payby'); +if ( $payby ) { + if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { + $cgi->param('payinfo', + $cgi->param($payby. '_payinfo1'). '@'. $cgi->param($payby. '_payinfo2') ); + } else { + $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) ); + } + $cgi->param('paydate', + $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) ); + $cgi->param('payname', $cgi->param( $payby. '_payname' ) ); + $cgi->param('paycvv', $cgi->param( $payby. '_paycvv' ) ) + if defined $cgi->param( $payby. '_paycvv' ); +} + +my @invoicing_list = split( /\s*\,\s*/, $cgi->param('invoicing_list') ); +push @invoicing_list, 'POST' if $cgi->param('invoicing_list_POST'); +$cgi->param('invoicing_list', join(',', @invoicing_list) ); + + +#create new record object + +my $new = new FS::cust_main ( { + map { + $_, scalar($cgi->param($_)) +# } qw(custnum agentnum last first ss company address1 address2 city county +# state zip daytime night fax payby payinfo paydate payname tax +# otaker refnum) + } fields('cust_main') +} ); + +if ( defined($cgi->param('same')) && $cgi->param('same') eq "Y" ) { + $new->setfield("ship_$_", '') foreach qw( + last first company address1 address2 city county state zip + country daytime night fax + ); +} + +#perhaps this stuff should go to cust_main.pm +my $cust_pkg = ''; +my $svc_acct = ''; +if ( $new->custnum eq '' ) { + + if ( $cgi->param('pkgpart_svcpart') ) { + my $x = $cgi->param('pkgpart_svcpart'); + $x =~ /^(\d+)_(\d+)$/ or die "illegal pkgpart_svcpart $x\n"; + my($pkgpart, $svcpart) = ($1, $2); + #false laziness: copied from FS::cust_pkg::order (which should become a + #FS::cust_main method) + my(%part_pkg); + # generate %part_pkg + # $part_pkg{$pkgpart} is true iff $custnum may purchase $pkgpart + my $agent = qsearchs('agent',{'agentnum'=> $new->agentnum }); + #my($type_pkgs); + #foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { + # my($pkgpart)=$type_pkgs->pkgpart; + # $part_pkg{$pkgpart}++; + #} + # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart + my $pkgpart_href = $agent->pkgpart_hashref; + #eslaf + + # this should wind up in FS::cust_pkg! + $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. ") can't ". + "purchase pkgpart ". $pkgpart + #unless $part_pkg{ $pkgpart }; + unless $pkgpart_href->{ $pkgpart }; + + $cust_pkg = new FS::cust_pkg ( { + #later 'custnum' => $custnum, + 'pkgpart' => $pkgpart, + } ); + #$error ||= $cust_pkg->check; + + #$cust_svc = new FS::cust_svc ( { 'svcpart' => $svcpart } ); + + #$error ||= $cust_svc->check; + + $svc_acct = new FS::svc_acct ( { + 'svcpart' => $svcpart, + 'username' => $cgi->param('username'), + '_password' => $cgi->param('_password'), + 'popnum' => $cgi->param('popnum'), + } ); + + my $y = $svc_acct->setdefault; # arguably should be in new method + $error ||= $y unless ref($y); + #and just in case you were silly + $svc_acct->svcpart($svcpart); + $svc_acct->username($cgi->param('username')); + $svc_acct->_password($cgi->param('_password')); + $svc_acct->popnum($cgi->param('popnum')); + + #$error ||= $svc_acct->check; + + } elsif ( $cgi->param('username') ) { #good thing to catch + $error = "Can't assign username without a package!"; + } + + use Tie::RefHash; + tie my %hash, 'Tie::RefHash'; + %hash = ( $cust_pkg => [ $svc_acct ] ) if $cust_pkg; + $error ||= $new->insert( \%hash, \@invoicing_list ); +} else { #create old record object + my $old = qsearchs( 'cust_main', { 'custnum' => $new->custnum } ); + $error ||= "Old record not found!" unless $old; + if ( defined dbdef->table('cust_main')->column('paycvv') + && length($old->paycvv) + && $new->paycvv =~ /^\s*\*+\s*$/ ) { + $new->paycvv($old->paycvv); + } + $error ||= $new->replace($old, \@invoicing_list); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_main.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?". $new->custnum); +} +%> diff --git a/httemplate/edit/process/cust_main_county-collapse.cgi b/httemplate/edit/process/cust_main_county-collapse.cgi new file mode 100755 index 000000000..5da9dea80 --- /dev/null +++ b/httemplate/edit/process/cust_main_county-collapse.cgi @@ -0,0 +1,35 @@ +<% + +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ or die "Illegal taxnum!"; +my $taxnum = $1; +my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } ) + or die "Unknown taxnum $taxnum"; + +#really should do this in a .pm & start transaction + +foreach my $delete ( qsearch('cust_main_county', { + 'country' => $cust_main_county->country, + 'state' => $cust_main_county->state + } ) ) { +# unless ( qsearch('cust_main',{ +# 'state' => $cust_main_county->getfield('state'), +# 'county' => $cust_main_county->getfield('county'), +# 'country' => $cust_main_county->getfield('country'), +# } ) ) { + my $error = $delete->delete; + die $error if $error; +# } else { + #should really fix the $cust_main record +# } + +} + +$cust_main_county->taxnum(''); +$cust_main_county->county(''); +my $error = $cust_main_county->insert; +die $error if $error; + +print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi"); + +%> diff --git a/httemplate/edit/process/cust_main_county-expand.cgi b/httemplate/edit/process/cust_main_county-expand.cgi new file mode 100755 index 000000000..a452711c1 --- /dev/null +++ b/httemplate/edit/process/cust_main_county-expand.cgi @@ -0,0 +1,58 @@ +<% + +$cgi->param('taxnum') =~ /^(\d+)$/ or die "Illegal taxnum!"; +my $taxnum = $1; +my $cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum}) + or die ("Unknown taxnum!"); + +my @expansion; +if ( $cgi->param('delim') eq 'n' ) { + @expansion=split(/\n/,$cgi->param('expansion')); +} elsif ( $cgi->param('delim') eq 's' ) { + @expansion=split(' ',$cgi->param('expansion')); +} else { + die "Illegal delim!"; +} + +@expansion=map { + unless ( /^\s*([\w\- ]+)\s*$/ ) { + $cgi->param('error', "Illegal item in expansion"); + print $cgi->redirect(popurl(2). "cust_main_county-expand.cgi?". $cgi->query_string ); + myexit(); + } + $1; +} @expansion; + +foreach ( @expansion) { + my(%hash)=$cust_main_county->hash; + my($new)=new FS::cust_main_county \%hash; + $new->setfield('taxnum',''); + if ( $cgi->param('taxclass') ) { + $new->setfield('taxclass', $_); + } elsif ( ! $cust_main_county->state ) { + $new->setfield('state',$_); + } else { + $new->setfield('county',$_); + } + #if (datasrc =~ m/Pg/) + #{ + # $new->setfield('tax',0.0); + #} + my($error)=$new->insert; + die $error if $error; +} + +unless ( qsearch( 'cust_main', { + 'state' => $cust_main_county->state, + 'county' => $cust_main_county->county, + 'country' => $cust_main_county->country, + } ) + || ! @expansion +) { + my($error)=($cust_main_county->delete); + die $error if $error; +} + +print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi"); + +%> diff --git a/httemplate/edit/process/cust_main_county.cgi b/httemplate/edit/process/cust_main_county.cgi new file mode 100755 index 000000000..9287ed150 --- /dev/null +++ b/httemplate/edit/process/cust_main_county.cgi @@ -0,0 +1,30 @@ +<% + +foreach ( grep { /^tax\d+$/ } $cgi->param ) { + /^tax(\d+)$/ or die "Illegal form $_!"; + my $taxnum = $1; + my $old = qsearchs('cust_main_county', { 'taxnum' => $taxnum }) + or die "Couldn't find taxnum $taxnum!"; + next unless $old->tax != $cgi->param("tax$taxnum") + || $old->exempt_amount != $cgi->param("exempt_amount$taxnum") + || $old->taxname ne $cgi->param("taxname$taxnum") + || $old->setuptax ne $cgi->param("setuptax$taxnum") + || $old->recurtax ne $cgi->param("recurtax$taxnum"); + my %hash = $old->hash; + $hash{tax} = $cgi->param("tax$taxnum"); + $hash{exempt_amount} = $cgi->param("exempt_amount$taxnum"); + $hash{taxname} = $cgi->param("taxname$taxnum"); + $hash{setuptax} = $cgi->param("setuptax$taxnum"); + $hash{recurtax} = $cgi->param("recurtax$taxnum"); + my $new = new FS::cust_main_county \%hash; + my $error = $new->replace($old); + if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_main_county.cgi?". $cgi->query_string ); + myexit(); + } +} + +print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi"); + +%> diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi new file mode 100755 index 000000000..82442ae00 --- /dev/null +++ b/httemplate/edit/process/cust_pay.cgi @@ -0,0 +1,39 @@ +<% + +$cgi->param('linknum') =~ /^(\d+)$/ + or die "Illegal linknum: ". $cgi->param('linknum'); +my $linknum = $1; + +$cgi->param('link') =~ /^(custnum|invnum)$/ + or die "Illegal link: ". $cgi->param('link'); +my $link = $1; + +my $new = new FS::cust_pay ( { + $link => $linknum, + map { + $_, scalar($cgi->param($_)); + } qw(paid _date payby payinfo paybatch) + #} fields('cust_pay') +} ); + +my $error = $new->insert; + +if ($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). 'cust_pay.cgi?'. $cgi->query_string ); +} elsif ( $link eq 'invnum' ) { + print $cgi->redirect(popurl(3). "view/cust_bill.cgi?$linknum"); +} elsif ( $link eq 'custnum' ) { + if ( $cgi->param('apply') eq 'yes' ) { + my $cust_main = qsearchs('cust_main', { 'custnum' => $linknum }) + or die "unknown custnum $linknum"; + $cust_main->apply_payments; + } + if ( $cgi->param('quickpay') eq 'yes' ) { + print $cgi->redirect(popurl(3). "search/cust_main-quickpay.html"); + } else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$linknum"); + } +} + +%> diff --git a/httemplate/edit/process/cust_pkg.cgi b/httemplate/edit/process/cust_pkg.cgi new file mode 100755 index 000000000..df8471c27 --- /dev/null +++ b/httemplate/edit/process/cust_pkg.cgi @@ -0,0 +1,43 @@ +<% + +my $error = ''; + +#untaint custnum +$cgi->param('custnum') =~ /^(\d+)$/; +my $custnum = $1; + +my @remove_pkgnums = map { + /^(\d+)$/ or die "Illegal remove_pkg value!"; + $1; +} $cgi->param('remove_pkg'); + +my $error_redirect; +my @pkgparts; +if ( $cgi->param('new_pkgpart') =~ /^(\d+)$/ ) { #came from misc/change_pkg.cgi + $error_redirect = "misc/change_pkg.cgi"; + @pkgparts = ($1); +} else { #came from edit/cust_pkg.cgi + $error_redirect = "edit/cust_pkg.cgi"; + foreach my $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) { + if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) { + my $num_pkgs = $1; + while ( $num_pkgs-- ) { + push @pkgparts,$pkgpart; + } + } else { + $error = "Illegal quantity"; + last; + } + } +} + +$error ||= FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums); + +if ($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(3). $error_redirect. '?'. $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} + +%> diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi new file mode 100755 index 000000000..7055d8ea6 --- /dev/null +++ b/httemplate/edit/process/cust_refund.cgi @@ -0,0 +1,42 @@ +<% + +$cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!"; +my $custnum = $1; +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "unknown custnum $custnum"; + +my $error = ''; +if ( $cgi->param('payby') =~ /^(CARD|CHEK)$/ ) { + my %payby2bop = ( + 'CARD' => 'CC', + 'CHEK' => 'ECHECK', + ); + my $bop = $payby2bop{$1}; + $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 $reason = $cgi->param('reason'); + $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund, + 'paynum' => $paynum, + 'reason' => $reason, ); +} else { + die 'unimplemented'; + #my $new = new FS::cust_refund ( { + # map { + # $_, scalar($cgi->param($_)); + # } ( fields('cust_refund'), 'paynum' ) + #} ); + #$error = $new->insert; +} + + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "cust_refund.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} + +%> diff --git a/httemplate/edit/process/cust_svc.cgi b/httemplate/edit/process/cust_svc.cgi new file mode 100644 index 000000000..187ede5e5 --- /dev/null +++ b/httemplate/edit/process/cust_svc.cgi @@ -0,0 +1,30 @@ +<% + +my $svcnum = $cgi->param('svcnum'); + +my $old = qsearchs('cust_svc',{'svcnum'=>$svcnum}) if $svcnum; + +my $new = new FS::cust_svc ( { + map { + $_, scalar($cgi->param($_)); + } fields('cust_svc') +} ); + +my $error; +if ( $svcnum ) { + $error=$new->replace($old); +} else { + $error=$new->insert; + $svcnum=$new->getfield('svcnum'); +} + +if ( $error ) { + #$cgi->param('error', $error); + #print $cgi->redirect(popurl(2). "cust_svc.cgi?". $cgi->query_string ); + eidiot($error); +} else { + my $svcdb = $new->part_svc->svcdb; + print $cgi->redirect(popurl(3). "view/$svcdb.cgi?$svcnum"); +} + + diff --git a/httemplate/edit/process/domain_record.cgi b/httemplate/edit/process/domain_record.cgi new file mode 100755 index 000000000..b8c3f62a1 --- /dev/null +++ b/httemplate/edit/process/domain_record.cgi @@ -0,0 +1,34 @@ +<% + +my $recnum = $cgi->param('recnum'); + +my $old = qsearchs('agent',{'recnum'=>$recnum}) if $recnum; + +my $new = new FS::domain_record ( { + map { + $_, scalar($cgi->param($_)); + } fields('domain_record') +} ); + +my $error; +if ( $recnum ) { + $error=$new->replace($old); +} else { + $error=$new->insert; + $recnum=$new->getfield('recnum'); +} + +if ( $error ) { +# $cgi->param('error', $error); +# print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string ); + #no edit screen to send them back to +%> +<!-- mason kludge --> +<% + eidiot($error); +} else { + my $svcnum = $new->svcnum; + print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum"); +} + +%> diff --git a/httemplate/edit/process/generic.cgi b/httemplate/edit/process/generic.cgi new file mode 100644 index 000000000..9c54feb1d --- /dev/null +++ b/httemplate/edit/process/generic.cgi @@ -0,0 +1,70 @@ +<% + +# Welcome to generic.cgi. +# +# This script provides a generic edit/process/ backend for simple table +# editing. All it knows how to do is take the values entered into +# the script and insert them into the table specified by $cgi->param('table'). +# If there's an existing record with the same primary key, it will be +# replaced. (Deletion will be added in the future.) +# +# Special cgi params for this script: +# table: the name of the table to be edited. The script will die horribly +# if it can't find the table. +# redirect_ok: URL to be displayed after a successful edit. The value of +# the record's primary key will be passed as a keyword. +# Defaults to (freeside root)/view/$table.cgi. +# redirect_error: URL to be displayed if there's an error. The original +# query string, plus the error message, will be passed. +# Defaults to $cgi->referer() (i.e. go back where you +# came from). + + +use FS::Record qw(qsearchs dbdef); +use DBIx::DBSchema; +use DBIx::DBSchema::Table; + + +my $error; +my $p2 = popurl(2); +my $p3 = popurl(3); +my $table = $cgi->param('table'); +my $dbdef = dbdef or die "Cannot fetch dbdef!"; + +my $dbdef_table = $dbdef->table($table) or die "Cannot fetch schema for $table"; + +my $pkey = $dbdef_table->primary_key or die "Cannot fetch pkey for $table"; +my $pkey_val = $cgi->param($pkey); + + +#warn "new FS::Record ( $table, (hashref) )"; +my $new = FS::Record::new ( "FS::$table", { + map { $_, scalar($cgi->param($_)) } fields($table) +} ); + +#warn 'created $new of class '.ref($new); + +if($pkey_val and (my $old = qsearchs($table, { $pkey, $pkey_val} ))) { + # edit + $error = $new->replace($old); +} else { + #add + $error = $new->insert; + $pkey_val = $new->getfield($pkey); + # New records usually don't have their primary keys set until after + # they've been checked/inserted, so grab the new $pkey_val so we can + # redirect to it. +} + +my $redirect_ok = (($cgi->param('redirect_ok')) ? + $cgi->param('redirect_ok') : $p3."browse/generic.cgi?$table"); +my $redirect_error = (($cgi->param('redirect_error')) ? + $cgi->param('redirect_error') : $cgi->referer()); + +if($error) { + $cgi->param('error', $error); + print $cgi->redirect($redirect_error . '?' . $cgi->query_string); +} else { + print $cgi->redirect($redirect_ok); +} +%> diff --git a/httemplate/edit/process/msgcat.cgi b/httemplate/edit/process/msgcat.cgi new file mode 100644 index 000000000..1f94f6668 --- /dev/null +++ b/httemplate/edit/process/msgcat.cgi @@ -0,0 +1,20 @@ +<% + +my $error; +foreach my $param ( grep { /^\d+$/ } $cgi->param ) { + my $old = qsearchs('msgcat', { msgnum=>$param } ); + next if $old->msg eq $cgi->param($param); #no need to update identical records + my $new = new FS::msgcat { $old->hash }; + $new->msg($cgi->param($param)); + $error = $new->replace($old); + last if $error; +} + +if ( $error ) { + $cgi->param('error',$error); + print $cgi->redirect($p. "msgcat.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/msgcat.cgi"); +} + +%> diff --git a/httemplate/edit/process/part_bill_event.cgi b/httemplate/edit/process/part_bill_event.cgi new file mode 100755 index 000000000..77dcd242a --- /dev/null +++ b/httemplate/edit/process/part_bill_event.cgi @@ -0,0 +1,54 @@ +<% + +my $eventpart = $cgi->param('eventpart'); + +my $old = qsearchs('part_bill_event',{'eventpart'=>$eventpart}) if $eventpart; + +#s/days/seconds/ +$cgi->param('seconds', int( $cgi->param('days') * 86400 ) ); + +my $error; +if ( ! $cgi->param('plan_weight_eventcode') ) { + $error = "Must select an action"; +} else { + + $cgi->param('plan_weight_eventcode') =~ /^([\w\-]+):(\d+):(.*)$/s + or die "illegal plan_weight_eventcode:". + $cgi->param('plan_weight_eventcode'); + $cgi->param('plan', $1); + $cgi->param('weight', $2); + my $eventcode = $3; + my $plandata = ''; + while ( $eventcode =~ /%%%(\w+)%%%/ ) { + my $field = $1; + my $value = join(', ', $cgi->param($field) ); + $cgi->param($field, $value); #in case it errors out + $eventcode =~ s/%%%$field%%%/$value/; + $plandata .= "$field $value\n"; + } + $cgi->param('eventcode', $eventcode); + $cgi->param('plandata', $plandata); + + my $new = new FS::part_bill_event ( { + map { + $_, scalar($cgi->param($_)); + } fields('part_bill_event'), + } ); + + if ( $eventpart ) { + $error = $new->replace($old); + } else { + $error = $new->insert; + $eventpart = $new->getfield('eventpart'); + } +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "part_bill_event.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3)."browse/part_bill_event.cgi"); +} + +%> + diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi new file mode 100644 index 000000000..fa009edbb --- /dev/null +++ b/httemplate/edit/process/part_export.cgi @@ -0,0 +1,39 @@ +<% + +my $exportnum = $cgi->param('exportnum'); + +my $old = qsearchs('part_export', { 'exportnum'=>$exportnum } ) if $exportnum; + +#fixup options +#warn join('-', split(',',$cgi->param('options'))); +my %options = map { + my $value = $cgi->param($_); + $value =~ s/\r\n/\n/g; #browsers? (textarea) + $_ => $value; +} split(',', $cgi->param('options')); + +my $new = new FS::part_export ( { + map { + $_, scalar($cgi->param($_)); + } fields('part_export') +} ); + +my $error; +if ( $exportnum ) { + #warn $old; + #warn $exportnum; + #warn $new->machine; + $error = $new->replace($old,\%options); +} else { + $error = $new->insert(\%options); +# $exportnum = $new->exportnum; +} + +if ( $error ) { + $cgi->param('error', $error ); + print $cgi->redirect(popurl(2). "part_export.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/part_export.cgi"); +} + +%> diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi new file mode 100755 index 000000000..5ff3e6f17 --- /dev/null +++ b/httemplate/edit/process/part_pkg.cgi @@ -0,0 +1,53 @@ +<% + +my $dbh = dbh; + +my $pkgpart = $cgi->param('pkgpart'); + +my $old = qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart; + +#fixup plandata +my $plandata = $cgi->param('plandata'); +my @plandata = split(',', $plandata); +$cgi->param('plandata', + join('', map { "$_=". join(', ', $cgi->param($_)). "\n" } @plandata ) +); + +foreach (qw( setuptax recurtax disabled )) { + $cgi->param($_, '') unless defined $cgi->param($_); +} + +my $new = new FS::part_pkg ( { + map { + $_, scalar($cgi->param($_)); + } fields('part_pkg') +} ); + +my %pkg_svc = map { $_ => $cgi->param("pkg_svc$_") } + map { $_->svcpart } + qsearch('part_svc', {} ); + +my $error; +my $custnum = ''; +if ( $pkgpart ) { + $error = $new->replace( $old, 'pkg_svc' => \%pkg_svc, + 'primary_svc' => $cgi->param('pkg_svc_primary'), + ); +} else { + $error = $new->insert( 'pkg_svc' => \%pkg_svc, + 'primary_svc' => $cgi->param('pkg_svc_primary'), + 'cust_pkg' => $cgi->param('pkgnum'), + 'custnum_ref' => \$custnum, + ); + $pkgpart = $new->pkgpart; +} +if ( $error ) { + $cgi->param('error', $error ); + print $cgi->redirect(popurl(2). "part_pkg.cgi?". $cgi->query_string ); +} elsif ( $custnum ) { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum"); +} else { + print $cgi->redirect(popurl(3). "browse/part_pkg.cgi"); +} + +%> diff --git a/httemplate/edit/process/part_referral.cgi b/httemplate/edit/process/part_referral.cgi new file mode 100755 index 000000000..fd2c01506 --- /dev/null +++ b/httemplate/edit/process/part_referral.cgi @@ -0,0 +1,28 @@ +<% + +my $refnum = $cgi->param('refnum'); + +my $new = new FS::part_referral ( { + map { + $_, scalar($cgi->param($_)); + } fields('part_referral') +} ); + +my $error; +if ( $refnum ) { + my $old = qsearchs( 'part_referral', { 'refnum' =>$ refnum } ); + die "(Old) Record not found!" unless $old; + $error = $new->replace($old); +} else { + $error = $new->insert; +} +$refnum=$new->refnum; + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "part_referral.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/part_referral.cgi"); +} + +%> diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi new file mode 100644 index 000000000..477f58508 --- /dev/null +++ b/httemplate/edit/process/quick-charge.cgi @@ -0,0 +1,32 @@ +<% + +#untaint custnum +$cgi->param('custnum') =~ /^(\d+)$/ + or die 'illegal custnum '. $cgi->param('custnum'); +my $custnum = $1; + +$cgi->param('amount') =~ /^\s*(\d+(\.\d{1,2})?)\s*$/ + or die 'illegal amount '. $cgi->param('amount'); +my $amount = $1; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "unknown custnum $custnum"; + +my $error = $cust_main->charge( + $amount, + $cgi->param('pkg'), + '$'. sprintf("%.2f",$amount), + $cgi->param('taxclass') +); + +if ($error) { +%> +<!-- mason kludge --> +<% + eidiot($error); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum" ); +} + +%> + diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi new file mode 100644 index 000000000..fd9e59472 --- /dev/null +++ b/httemplate/edit/process/quick-cust_pkg.cgi @@ -0,0 +1,25 @@ +<% + +#untaint custnum +$cgi->param('custnum') =~ /^(\d+)$/ + or die 'illegal custnum '. $cgi->param('custnum'); +my $custnum = $1; +$cgi->param('pkgpart') =~ /^(\d+)$/ + or die 'illegal pkgpart '. $cgi->param('pkgpart'); +my $pkgpart = $1; + +my @cust_pkg = (); +my $error = FS::cust_pkg::order($custnum, [ $pkgpart ], [], \@cust_pkg, ); + +if ($error) { +%> +<!-- mason kludge --> +<% + eidiot($error); +} else { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum". + "#cust_pkg". $cust_pkg[0]->pkgnum ); +} + +%> + diff --git a/httemplate/edit/process/rate.cgi b/httemplate/edit/process/rate.cgi new file mode 100755 index 000000000..04ff5f8f7 --- /dev/null +++ b/httemplate/edit/process/rate.cgi @@ -0,0 +1,37 @@ +<% + +my $ratenum = $cgi->param('ratenum'); + +my $old = qsearchs('rate', { 'ratenum' => $ratenum } ) if $ratenum; + +my @rate_detail = map { + my $regionnum = $_->regionnum; + new FS::rate_detail { + 'dest_regionnum' => $regionnum, + map { $_ => $cgi->param("$_$regionnum") } + qw( min_included min_charge sec_granularity ) + }; +} qsearch('rate_region', {} ); + +my $new = new FS::rate ( { + map { + $_, scalar($cgi->param($_)); + } fields('rate') +} ); + +my $error; +if ( $ratenum ) { + $error = $new->replace($old, 'rate_detail' => \@rate_detail ); +} else { + $error = $new->insert( 'rate_detail' => \@rate_detail ); + $ratenum = $new->getfield('ratenum'); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "rate.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/rate.cgi"); +} + +%> diff --git a/httemplate/edit/process/rate_region.cgi b/httemplate/edit/process/rate_region.cgi new file mode 100755 index 000000000..09d3d2c42 --- /dev/null +++ b/httemplate/edit/process/rate_region.cgi @@ -0,0 +1,51 @@ +<% + +my $regionnum = $cgi->param('regionnum'); + +my $old = qsearchs('rate_region', { 'regionnum' => $regionnum } ) if $regionnum; + +my $new = new FS::rate_region ( { + map { + $_, scalar($cgi->param($_)); + } ( fields('rate_region') ) +} ); + +my $countrycode = $cgi->param('countrycode'); +my @npa = split(/\s*,\s*/, $cgi->param('npa')); +$npa[0] = '' unless @npa; +my @rate_prefix = map { + new FS::rate_prefix { + 'countrycode' => $countrycode, + 'npa' => $_, + } + } @npa; + +my @dest_detail = map { + my $ratenum = $_->ratenum; + new FS::rate_detail { + 'ratenum' => $ratenum, + map { $_ => $cgi->param("$_$ratenum") } + qw( min_included min_charge sec_granularity ) + }; +} qsearch('rate', {} ); + + +my $error; +if ( $regionnum ) { + $error = $new->replace($old, 'rate_prefix' => \@rate_prefix, + 'dest_detail' => \@dest_detail, ); +} else { + $error = $new->insert( 'rate_prefix' => \@rate_prefix, + 'dest_detail' => \@dest_detail, ); + $regionnum = $new->getfield('regionnum'); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "rate_region.cgi?". $cgi->query_string ); +} else { + #print $cgi->redirect(popurl(3). "browse/rate_region.cgi"); + print $cgi->redirect(popurl(3). "browse/rate.cgi"); +} + +%> diff --git a/httemplate/edit/process/router.cgi b/httemplate/edit/process/router.cgi new file mode 100644 index 000000000..a2fa46dd9 --- /dev/null +++ b/httemplate/edit/process/router.cgi @@ -0,0 +1,67 @@ +<% + +local $FS::UID::AutoCommit=0; + +sub check { + my $error = shift; + if($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(3) . "edit/router.cgi?". $cgi->query_string); + dbh->rollback; + exit; + } +} + +my $error = ''; +my $routernum = $cgi->param('routernum'); +my $routername = $cgi->param('routername'); +my $old = qsearchs('router', { routernum => $routernum }); +my @old_psr; + +my $new = new FS::router { + map { + ($_, scalar($cgi->param($_))); + } fields('router') +}; + +if($old) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $routernum = $new->routernum; +} + +check($error); + +if ($old) { + @old_psr = $old->part_svc_router; + foreach my $psr (@old_psr) { + if($cgi->param('svcpart_'.$psr->svcpart) eq 'ON') { + # do nothing + } else { + $error = $psr->delete; + } + } + check($error); +} + +foreach($cgi->param) { + if($cgi->param($_) eq 'ON' and /^svcpart_(\d+)$/) { + my $svcpart = $1; + if(grep {$_->svcpart == $svcpart} @old_psr) { + # do nothing + } else { + my $new_psr = new FS::part_svc_router { svcpart => $svcpart, + routernum => $routernum }; + $error = $new_psr->insert; + } + check($error); + } +} + + +# Yay, everything worked! +dbh->commit or die dbh->errstr; +print $cgi->redirect(popurl(3). "browse/router.cgi"); + +%> diff --git a/httemplate/edit/process/svc_acct.cgi b/httemplate/edit/process/svc_acct.cgi new file mode 100755 index 000000000..950a8602f --- /dev/null +++ b/httemplate/edit/process/svc_acct.cgi @@ -0,0 +1,49 @@ +<% + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum = $1; + +my $old; +if ( $svcnum ) { + $old = qsearchs('svc_acct', { 'svcnum' => $svcnum } ) + or die "fatal: can't find account (svcnum $svcnum)!"; +} else { + $old = ''; +} + +#unmunge popnum +$cgi->param('popnum', (split(/:/, $cgi->param('popnum') ))[0] ); + +#unmunge passwd +if ( $cgi->param('_password') eq '*HIDDEN*' ) { + die "fatal: no previous account to recall hidden password from!" unless $old; + $cgi->param('_password',$old->getfield('_password')); +} + +#unmunge usergroup +$cgi->param('usergroup', [ $cgi->param('radius_usergroup') ] ); + +my $new = new FS::svc_acct ( { + map { + $_, scalar($cgi->param($_)); + #} qw(svcnum pkgnum svcpart username _password popnum uid gid finger dir + # shell quota slipip) + } ( fields('svc_acct'), qw( pkgnum svcpart usergroup ) ) +} ); + +my $error; +if ( $svcnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $svcnum = $new->svcnum; +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_acct.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/svc_acct.cgi?" . $svcnum ); +} + +%> diff --git a/httemplate/edit/process/svc_acct_pop.cgi b/httemplate/edit/process/svc_acct_pop.cgi new file mode 100755 index 000000000..46ad74d62 --- /dev/null +++ b/httemplate/edit/process/svc_acct_pop.cgi @@ -0,0 +1,28 @@ +<% + +my $popnum = $cgi->param('popnum'); + +my $old = qsearchs('svc_acct_pop',{'popnum'=>$popnum}) if $popnum; + +my $new = new FS::svc_acct_pop ( { + map { + $_, scalar($cgi->param($_)); + } fields('svc_acct_pop') +} ); + +my $error = ''; +if ( $popnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $popnum=$new->getfield('popnum'); +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_acct_pop.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "browse/svc_acct_pop.cgi"); +} + +%> diff --git a/httemplate/edit/process/svc_broadband.cgi b/httemplate/edit/process/svc_broadband.cgi new file mode 100644 index 000000000..4912a3a9f --- /dev/null +++ b/httemplate/edit/process/svc_broadband.cgi @@ -0,0 +1,45 @@ +<% + +# If it's stupid but it works, it's not stupid. +# -- U.S. Army + +local $FS::UID::AutoCommit = 0; +my $dbh = FS::UID::dbh; + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum = $1; + +my $old; +if ( $svcnum ) { + $old = qsearchs('svc_broadband', { 'svcnum' => $svcnum } ) + or die "fatal: can't find broadband service (svcnum $svcnum)!"; +} else { + $old = ''; +} + +my $new = new FS::svc_broadband ( { + map { + ($_, scalar($cgi->param($_))); + } ( fields('svc_broadband'), qw( pkgnum svcpart ) ) +} ); + +my $error; +if ( $svcnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $svcnum = $new->svcnum; +} + + +if ( $error ) { + $cgi->param('error', $error); + $cgi->param('ip_addr', $new->ip_addr); + $dbh->rollback; + print $cgi->redirect(popurl(2). "svc_broadband.cgi?". $cgi->query_string ); +} else { + $dbh->commit or die $dbh->errstr; + print $cgi->redirect(popurl(3). "view/svc_broadband.cgi?" . $svcnum ); +} + +%> diff --git a/httemplate/edit/process/svc_domain.cgi b/httemplate/edit/process/svc_domain.cgi new file mode 100755 index 000000000..19f8eb4f8 --- /dev/null +++ b/httemplate/edit/process/svc_domain.cgi @@ -0,0 +1,31 @@ +<% + +#remove this to actually test the domains! +$FS::svc_domain::whois_hack = 1; + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum = $1; + +my $new = new FS::svc_domain ( { + map { + $_, scalar($cgi->param($_)); + #} qw(svcnum pkgnum svcpart domain action purpose) + } ( fields('svc_domain'), qw( pkgnum svcpart action purpose ) ) +} ); + +my $error = ''; +if ($cgi->param('svcnum')) { + $error="Can't modify a domain!"; +} else { + $error=$new->insert; + $svcnum=$new->svcnum; +} + +if ($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_domain.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum"); +} + +%> diff --git a/httemplate/edit/process/svc_external.cgi b/httemplate/edit/process/svc_external.cgi new file mode 100755 index 000000000..728cd2189 --- /dev/null +++ b/httemplate/edit/process/svc_external.cgi @@ -0,0 +1,29 @@ +<% + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum =$1; + +my $old = qsearchs('svc_external',{'svcnum'=>$svcnum}) if $svcnum; + +my $new = new FS::svc_external ( { + map { + ($_, scalar($cgi->param($_))); + } ( fields('svc_external'), qw( pkgnum svcpart ) ) +} ); + +my $error = ''; +if ( $svcnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $svcnum = $new->getfield('svcnum'); +} + +if ($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_external.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/svc_external.cgi?$svcnum"); +} + +%> diff --git a/httemplate/edit/process/svc_forward.cgi b/httemplate/edit/process/svc_forward.cgi new file mode 100755 index 000000000..bb066d8a6 --- /dev/null +++ b/httemplate/edit/process/svc_forward.cgi @@ -0,0 +1,29 @@ +<% + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum =$1; + +my $old = qsearchs('svc_forward',{'svcnum'=>$svcnum}) if $svcnum; + +my $new = new FS::svc_forward ( { + map { + ($_, scalar($cgi->param($_))); + } ( fields('svc_forward'), qw( pkgnum svcpart ) ) +} ); + +my $error = ''; +if ( $svcnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $svcnum = $new->getfield('svcnum'); +} + +if ($error) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_forward.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/svc_forward.cgi?$svcnum"); +} + +%> diff --git a/httemplate/edit/process/svc_www.cgi b/httemplate/edit/process/svc_www.cgi new file mode 100644 index 000000000..40913145a --- /dev/null +++ b/httemplate/edit/process/svc_www.cgi @@ -0,0 +1,36 @@ +<% + +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum = $1; + +my $old; +if ( $svcnum ) { + $old = qsearchs('svc_www', { 'svcnum' => $svcnum } ) + or die "fatal: can't find website (svcnum $svcnum)!"; +} else { + $old = ''; +} + +my $new = new FS::svc_www ( { + map { + ($_, scalar($cgi->param($_))); + #} qw(svcnum pkgnum svcpart recnum usersvc) + } ( fields('svc_www'), qw( pkgnum svcpart ) ) +} ); + +my $error; +if ( $svcnum ) { + $error = $new->replace($old); +} else { + $error = $new->insert; + $svcnum = $new->svcnum; +} + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(2). "svc_www.cgi?". $cgi->query_string ); +} else { + print $cgi->redirect(popurl(3). "view/svc_www.cgi?" . $svcnum ); +} + +%> diff --git a/httemplate/edit/rate.cgi b/httemplate/edit/rate.cgi new file mode 100644 index 000000000..83a89c475 --- /dev/null +++ b/httemplate/edit/rate.cgi @@ -0,0 +1,94 @@ +<!-- mason kludge --> +<% + +my $rate; +if ( $cgi->param('error') ) { + $rate = new FS::rate ( { + map { $_, scalar($cgi->param($_)) } fields('rate') + } ); +} elsif ( $cgi->keywords ) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $rate = qsearchs( 'rate', { 'ratenum' => $1 } ); +} else { #adding + $rate = new FS::rate {}; +} +my $action = $rate->ratenum ? 'Edit' : 'Add'; + +my $p1 = popurl(1); + +my %granularity = ( + '6' => '6 second', + '60' => 'minute', +); + +%> + +<%= header("$action Rate plan", menubar( + 'Main Menu' => $p, + 'View all rate plans' => "${p}browse/rate.cgi", + )) +%> + +<% if ( $cgi->param('error') ) { %> +<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT><BR> +<% } %> + +<FORM ACTION="<%=$p1%>process/rate.cgi" METHOD=POST> + +<INPUT TYPE="hidden" NAME="ratenum" VALUE="<%= $rate->ratenum %>"> + +Rate plan +<INPUT TYPE="text" NAME="ratename" SIZE=32 VALUE="<%= $rate->ratename %>"> +<BR><BR> + +<%= table() %> +<TR> + <TH>Region</TH> + <TH>Prefix(es)</TH> + <TH><FONT SIZE=-1>Included<BR>minutes</FONT></TH> + <TH><FONT SIZE=-1>Charge per<BR>minute</FONT></TH> + <TH><FONT SIZE=-1>Granularity</FONT></TH> +</TR> + +<% foreach my $rate_region ( + qsearch('rate_region', {}, '', 'ORDER BY regionname' ) + ) { + my $n = $rate_region->regionnum; + my $rate_detail = + $rate->dest_detail($rate_region) + || new FS::rate_region { 'min_included' => 0, + 'min_charge' => 0, + 'sec_granularity' => '60' + }; +%> + <TR> + <TD><A HREF="<%=$p%>edit/rate_region.cgi?<%= $rate_region->regionnum %>"><%= $rate_region->regionname %></A></TD> + <TD><%= $rate_region->prefixes_short %></TD> + <TD><INPUT TYPE="text" SIZE=5 NAME="min_included<%=$n%>" VALUE="<%= $cgi->param("min_included$n") || $rate_detail->min_included %>"></TD> + <TD>$<INPUT TYPE="text" SIZE=4 NAME="min_charge<%=$n%>" VALUE="<%= sprintf('%.2f', $cgi->param("min_charge$n") || $rate_detail->min_charge ) %>"></TD> + <TD> + <SELECT NAME="sec_granularity<%=$n%>"> + <% foreach my $granularity ( keys %granularity ) { %> + <OPTION VALUE="<%=$granularity%>"<%= $granularity == ( $cgi->param("sec_granularity$n") || $rate_detail->sec_granularity ) ? ' SELECTED' : '' %>><%=$granularity{$granularity}%> + <% } %> + </SELECT> + </TR> +<% } %> + +<TR> + <TD COLSPAN=5 ALIGN="center"> + <A HREF="<%=$p%>edit/rate_region.cgi"><I>Add a region</I></A> + </TD> +</TR> + +</TABLE> + +<BR><INPUT TYPE="submit" VALUE="<%= + $rate->ratenum ? "Apply changes" : "Add rate plan" +%>"> + + </FORM> + </BODY> +</HTML> + diff --git a/httemplate/edit/rate_region.cgi b/httemplate/edit/rate_region.cgi new file mode 100644 index 000000000..cc14dd37d --- /dev/null +++ b/httemplate/edit/rate_region.cgi @@ -0,0 +1,114 @@ +<!-- mason kludge --> +<% + +my $rate_region; +if ( $cgi->param('error') ) { + $rate_region = new FS::rate_region ( { + map { $_, scalar($cgi->param($_)) } fields('rate_region') + } ); +} elsif ( $cgi->keywords ) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $rate_region = qsearchs( 'rate_region', { 'regionnum' => $1 } ); +} else { #adding + $rate_region = new FS::rate_region {}; +} +my $action = $rate_region->regionnum ? 'Edit' : 'Add'; + +my $p1 = popurl(1); + +my %granularity = ( + '6' => '6 second', + '60' => 'minute', +); + +my @rate_prefix = $rate_region->rate_prefix; +my $countrycode = ''; +if ( @rate_prefix ) { + $countrycode = $rate_prefix[0]->countrycode; + foreach my $rate_prefix ( @rate_prefix ) { + eidiot 'multiple country codes per region not yet supported by web UI' + unless $rate_prefix->countrycode eq $countrycode; + } +} + +%> + +<%= header("$action Region", menubar( + 'Main Menu' => $p, + #'View all regions' => "${p}browse/rate_region.cgi", + )) +%> + +<% if ( $cgi->param('error') ) { %> +<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT><BR> +<% } %> + +<FORM ACTION="<%=$p1%>process/rate_region.cgi" METHOD=POST> + +<INPUT TYPE="hidden" NAME="regionnum" VALUE="<%= $rate_region->regionnum %>"> + +<%= ntable('#cccccc') %> +<TR> + <TH ALIGN="right">Region name</TH> + <TD><INPUT TYPE="text" NAME="regionname" SIZE=32 VALUE="<%= $rate_region->regionname %>"></TR> +</TR> + +<TR> + <TH ALIGN="right">Country code</TH> + <TD><INPUT TYPE="text" NAME="countrycode" SIZE=4 MAXLENGTH=3 VALUE="<%= $countrycode %>"></TR> +</TR> + + +<TR> + <TH ALIGN="right">Prefixes</TH> + <TD> + <TEXTAREA NAME="npa" WRAP=SOFT><%= join(', ', map $_->npa, @rate_prefix ) %></TEXTAREA> + </TD> +</TR> + +</TABLE> + +<BR> +<%= table() %> +<TR> + <TH>Rate plan</TH> + <TH><FONT SIZE=-1>Included<BR>minutes</FONT></TH> + <TH><FONT SIZE=-1>Charge per<BR>minute</FONT></TH> + <TH><FONT SIZE=-1>Granularity</FONT></TH> +</TR> + +<% foreach my $rate ( qsearch('rate', {}) ) { + + my $n = $rate->ratenum; + my $rate_detail = $rate->dest_detail($rate_region) + || new FS::rate_region { 'min_included' => 0, + 'min_charge' => 0, + 'sec_granularity' => '60' + }; + +%> + <TR> + <TD><A HREF="<%=$p%>edit/rate.cgi?<%= $rate->ratenum %>"><%= $rate->ratename %></TD> + <TD><INPUT TYPE="text" SIZE=5 NAME="min_included<%=$n%>" VALUE="<%= $cgi->param("min_included$n") || $rate_detail->min_included %>"></TD> + <TD>$<INPUT TYPE="text" SIZE=4 NAME="min_charge<%=$n%>" VALUE="<%= sprintf('%.2f', $cgi->param("min_charge$n") || $rate_detail->min_charge ) %>"></TD> + <TD> + <SELECT NAME="sec_granularity<%=$n%>"> + <% foreach my $granularity ( keys %granularity ) { %> + <OPTION VALUE="<%=$granularity%>"<%= $granularity == ( $cgi->param("sec_granularity$n") || $rate_detail->sec_granularity ) ? ' SELECTED' : '' %>><%=$granularity{$granularity}%> + <% } %> + </SELECT> + </TR> +<% } %> + +</TABLE> + +<BR><BR><INPUT TYPE="submit" VALUE="<%= + $rate_region->regionnum ? "Apply changes" : "Add region" +%>"> + + </FORM> + </BODY> +</HTML> + + diff --git a/httemplate/edit/router.cgi b/httemplate/edit/router.cgi new file mode 100755 index 000000000..a573c6504 --- /dev/null +++ b/httemplate/edit/router.cgi @@ -0,0 +1,77 @@ +<HTML><BODY> + +<% + +my $router; +if ( $cgi->keywords ) { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/; + $router = qsearchs('router', { routernum => $1 }) + or print $cgi->redirect(popurl(2)."browse/router.cgi") ; +} else { + $router = new FS::router ( { + map { $_, scalar($cgi->param($_)) } fields('router') + } ); +} + +my $routernum = $router->routernum; +my $action = $routernum ? 'Edit' : 'Add'; + +print header("$action Router", menubar( + 'Main Menu' => "$p", + 'View all routers' => "${p}browse/router.cgi", +)); + +my $p3 = popurl(3); + +if($cgi->param('error')) { +%> <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT> +<% } %> + +<FORM ACTION="<%=popurl(1)%>process/router.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="table" VALUE="router"> + <INPUT TYPE="hidden" NAME="redirect_ok" VALUE="<%=$p3%>/browse/router.cgi"> + <INPUT TYPE="hidden" NAME="redirect_error" VALUE="<%=$p3%>/edit/router.cgi"> + <INPUT TYPE="hidden" NAME="routernum" VALUE="<%=$routernum%>"> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$router->svcnum%>"> + Router #<%=$routernum or "(NEW)"%> + +<BR><BR>Name <INPUT TYPE="text" NAME="routername" SIZE=32 VALUE="<%=$router->routername%>"> + +<BR><BR> +Custom fields: +<BR> +<%=table() %> + +<% +foreach my $field ($router->virtual_fields) { + print $router->pvf($field)->widget('HTML', 'edit', + $router->getfield($field)); +} +%> +</TABLE> + + +<% +unless ($router->svcnum) { +%> +<BR><BR>Select the service types available on this router<BR> +<% + + foreach my $part_svc ( qsearch('part_svc', { svcdb => 'svc_broadband', + disabled => '' }) ) { + %> + <BR> + <INPUT TYPE="checkbox" NAME="svcpart_<%=$part_svc->svcpart%>"<%= + qsearchs('part_svc_router', { svcpart => $part_svc->svcpart, + routernum => $routernum } ) ? ' CHECKED' : ''%> VALUE="ON"> + <A HREF="<%=${p}%>edit/part_svc.cgi?<%=$part_svc->svcpart%>"> + <%=$part_svc->svcpart%>: <%=$part_svc->svc%></A> + <% } %> + +<% } %> + + <BR><BR><INPUT TYPE="submit" VALUE="Apply changes"> + </FORM> +</BODY></HTML> + diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi new file mode 100755 index 000000000..f1b8b800b --- /dev/null +++ b/httemplate/edit/svc_acct.cgi @@ -0,0 +1,301 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; +my @shells = $conf->config('shells'); + +my($svcnum, $pkgnum, $svcpart, $part_svc, $svc_acct, @groups); +if ( $cgi->param('error') ) { + $svc_acct = new FS::svc_acct ( { + map { $_, scalar($cgi->param($_)) } fields('svc_acct') + } ); + $svcnum = $svc_acct->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } ); + die "No part_svc entry for svcpart $svcpart!" unless $part_svc; + @groups = $cgi->param('radius_usergroup'); +} else { + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_acct=qsearchs('svc_acct',{'svcnum'=>$svcnum}) + or die "Unknown (svc_acct) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } ); + die "No part_svc entry for svcpart $svcpart!" unless $part_svc; + + @groups = $svc_acct->radius_groups; + + } else { #adding + + foreach $_ (split(/-/,$query)) { + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } ); + die "No part_svc entry for svcpart $svcpart!" unless $part_svc; + + $svc_acct = new FS::svc_acct({svcpart => $svcpart}); + + $svcnum=''; + + #set gecos + my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + if ($cust_pkg) { + my($cust_main)=qsearchs('cust_main',{'custnum'=> $cust_pkg->custnum } ); + unless ( $part_svc->part_svc_column('uid')->columnflag eq 'F' ) { + $svc_acct->setfield('finger', + $cust_main->getfield('first') . " " . $cust_main->getfield('last') + ); + } + } + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + if ( $part_svc_column->columnname eq 'usergroup' ) { + @groups = split(',', $part_svc_column->columnvalue); + } else { + $svc_acct->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + } + + } +} + +#fixed radius groups always override & display +if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) { + @groups = split(',', $part_svc->part_svc_column('usergroup')->columnvalue); +} + +my $action = $svcnum ? 'Edit' : 'Add'; + +my $svc = $part_svc->getfield('svc'); + +my $otaker = getotaker; + +my $username = $svc_acct->username; +my $password; +if ( $svc_acct->_password ) { + if ( $conf->exists('showpasswords') || ! $svcnum ) { + $password = $svc_acct->_password; + } else { + $password = "*HIDDEN*"; + } +} else { + $password = ''; +} + +my $ulen = $conf->config('usernamemax') + || $svc_acct->dbdef_table->column('username')->length; +my $ulen2 = $ulen+2; + +my $pmax = $conf->config('passwordmax') || 8; +my $pmax2 = $pmax+2; + +my $p1 = popurl(1); +print header("$action $svc account"); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT><BR><BR>" + if $cgi->param('error'); + +print 'Service # '. ( $svcnum ? "<B>$svcnum</B>" : " (NEW)" ). '<BR>'. + 'Service: <B>'. $part_svc->svc. '</B><BR><BR>'. + <<END; + <FORM NAME="OneTrueForm" ACTION="${p1}process/svc_acct.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum"> + <INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum"> + <INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart"> +END + +print &ntable("#cccccc",2), <<END; +<TR><TD ALIGN="right">Username</TD> +<TD><INPUT TYPE="text" NAME="username" VALUE="$username" SIZE=$ulen2 MAXLENGTH=$ulen></TD></TR> +<TR><TD ALIGN="right">Password</TD> +<TD><INPUT TYPE="text" NAME="_password" VALUE="$password" SIZE=$pmax2 MAXLENGTH=$pmax> +(blank to generate)</TD> +</TR> +END + +my $sec_phrase = $svc_acct->sec_phrase; +if ( $conf->exists('security_phrase') ) { + print <<END; + <TR><TD ALIGN="right">Security phrase</TD> + <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase" SIZE=32> + (for forgotten passwords)</TD> + </TD> +END +} else { + print qq!<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="$sec_phrase">!; +} + +#domain +my $domsvc = $svc_acct->domsvc || 0; +if ( $part_svc->part_svc_column('domsvc')->columnflag eq 'F' ) { + print qq!<INPUT TYPE="hidden" NAME="domsvc" VALUE="$domsvc">!; +} else { + my %svc_domain = (); + + if ( $domsvc ) { + my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $domsvc, } ); + if ( $svc_domain ) { + $svc_domain{$svc_domain->svcnum} = $svc_domain; + } else { + warn "unknown svc_domain.svcnum for svc_acct.domsvc: $domsvc"; + } + } + + if ( $part_svc->part_svc_column('domsvc')->columnflag eq 'D' ) { + my $svc_domain = qsearchs('svc_domain', { + 'svcnum' => $part_svc->part_svc_column('domsvc')->columnvalue, + } ); + if ( $svc_domain ) { + $svc_domain{$svc_domain->svcnum} = $svc_domain; + } else { + warn "unknown svc_domain.svcnum for part_svc_column domsvc: ". + $part_svc->part_svc_column('domsvc')->columnvalue; + } + } + + my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $pkgnum } ); + if ($cust_pkg && !$conf->exists('svc_acct-alldomains') ) { + my @cust_svc = + map { qsearch('cust_svc', { 'pkgnum' => $_->pkgnum } ) } + qsearch('cust_pkg', { 'custnum' => $cust_pkg->custnum } ); + foreach my $cust_svc ( @cust_svc ) { + my $svc_domain = + qsearchs('svc_domain', { 'svcnum' => $cust_svc->svcnum } ); + $svc_domain{$svc_domain->svcnum} = $svc_domain if $svc_domain; + } + } else { + %svc_domain = map { $_->svcnum => $_ } qsearch('svc_domain', {} ); + } + print qq!<TR><TD ALIGN="right">Domain</TD>!. + qq!<TD><SELECT NAME="domsvc" SIZE=1>\n!; + foreach my $svcnum ( + sort { $svc_domain{$a}->domain cmp $svc_domain{$b}->domain } + keys %svc_domain + ) { + my $svc_domain = $svc_domain{$svcnum}; + print qq!<OPTION VALUE="!. $svc_domain->svcnum. qq!"!. + ( $svc_domain->svcnum == $domsvc ? ' SELECTED' : '' ). + '>'. $svc_domain->domain. "\n" ; + } + print "</SELECT></TD></TR>"; +} + +#pop +my $popnum = $svc_acct->popnum || 0; +if ( $part_svc->part_svc_column('popnum')->columnflag eq "F" ) { + print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$popnum">!; +} else { + print qq!<TR><TD ALIGN="right">Access number</TD>!. + qq!<TD>!. FS::svc_acct_pop::popselector($popnum). '</TD></TR>'; +} + +my($uid,$gid,$finger,$dir)=( + $svc_acct->uid, + $svc_acct->gid, + $svc_acct->finger, + $svc_acct->dir, +); + +print <<END; +<INPUT TYPE="hidden" NAME="uid" VALUE="$uid"> +<INPUT TYPE="hidden" NAME="gid" VALUE="$gid"> +END + +if ( !$finger && $part_svc->part_svc_column('uid')->columnflag eq 'F' ) { + print '<INPUT TYPE="hidden" NAME="finger" VALUE="">'; +} else { + print '<TR><TD ALIGN="right">GECOS</TD>'. + qq!<TD><INPUT TYPE="text" NAME="finger" VALUE="$finger"></TD></TR>!; +} +print qq!<INPUT TYPE="hidden" NAME="dir" VALUE="$dir">!; + +my $shell = $svc_acct->shell; +if ( $part_svc->part_svc_column('shell')->columnflag eq "F" + || ( !$shell && $part_svc->part_svc_column('uid')->columnflag eq 'F' ) + ) { + print qq!<INPUT TYPE="hidden" NAME="shell" VALUE="$shell">!; +} else { + print qq!<TR><TD ALIGN="right">Shell</TD><TD><SELECT NAME="shell" SIZE=1>!; + my($etc_shell); + foreach $etc_shell (@shells) { + print "<OPTION", $etc_shell eq $shell ? ' SELECTED' : '', ">", + $etc_shell, "\n"; + } + print "</SELECT></TD></TR>"; +} + +my($quota,$slipip)=( + $svc_acct->quota, + $svc_acct->slipip, +); + +if ( $part_svc->part_svc_column('quota')->columnflag eq "F" ) +{ + print qq!<INPUT TYPE="hidden" NAME="quota" VALUE="$quota">!; +} else { + print <<END; + <TR><TD ALIGN="right">Quota:</TD> + <TD> <INPUT TYPE="text" NAME="quota" VALUE="$quota" ></TD> + </TR> +END +} + +if ( $part_svc->part_svc_column('slipip')->columnflag eq "F" ) { + print qq!<INPUT TYPE="hidden" NAME="slipip" VALUE="$slipip">!; +} else { + print qq!<TR><TD ALIGN="right">IP</TD><TD><INPUT TYPE="text" NAME="slipip" VALUE="$slipip"></TD></TR>!; +} + +foreach my $r ( grep { /^r(adius|[cr])_/ } fields('svc_acct') ) { + $r =~ /^^r(adius|[cr])_(.+)$/ or next; #? + my $a = $2; + if ( $part_svc->part_svc_column($r)->columnflag eq 'F' ) { + print qq!<INPUT TYPE="hidden" NAME="$r" VALUE="!. + $svc_acct->getfield($r). '">'; + } else { + print qq!<TR><TD ALIGN="right">$FS::raddb::attrib{$a}</TD><TD><INPUT TYPE="text" NAME="$r" VALUE="!. + $svc_acct->getfield($r). '"></TD></TR>'; + } +} + +print '<TR><TD ALIGN="right">RADIUS groups</TD>'; +if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) { + print '<TD BGCOLOR="#ffffff">'. join('<BR>', @groups); +} else { + print '<TD>'. &FS::svc_acct::radius_usergroup_selector( \@groups ); +} +print '</TD></TR>'; + +foreach my $field ($svc_acct->virtual_fields) { + if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { + # If the flag is X, it won't even show up in $svc_acct->virtual_fields. + print $svc_acct->pvf($field)->widget('HTML', 'edit', + $svc_acct->getfield($field)); + } +} + +#submit +print qq!</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">!; + +print <<END; + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/svc_acct_pop.cgi b/httemplate/edit/svc_acct_pop.cgi new file mode 100755 index 000000000..399502a70 --- /dev/null +++ b/httemplate/edit/svc_acct_pop.cgi @@ -0,0 +1,56 @@ +<!-- mason kludge --> +<% + +my $svc_acct_pop; +if ( $cgi->param('error') ) { + $svc_acct_pop = new FS::svc_acct_pop ( { + map { $_, scalar($cgi->param($_)) } fields('svc_acct_pop') + } ); +} elsif ( $cgi->keywords ) { #editing + my($query)=$cgi->keywords; + $query =~ /^(\d+)$/; + $svc_acct_pop=qsearchs('svc_acct_pop',{'popnum'=>$1}); +} else { #adding + $svc_acct_pop = new FS::svc_acct_pop {}; +} +my $action = $svc_acct_pop->popnum ? 'Edit' : 'Add'; +my $hashref = $svc_acct_pop->hashref; + +my $p1 = popurl(1); +print header("$action Access Number", menubar( + 'Main Menu' => popurl(2), + 'View all Access Numbers' => popurl(2). "browse/svc_acct_pop.cgi", +)); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="${p1}process/svc_acct_pop.cgi" METHOD=POST>!; + +#display + +print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$hashref->{popnum}">!, + "POP #", $hashref->{popnum} ? $hashref->{popnum} : "(NEW)"; + +print <<END; +<PRE> +City <INPUT TYPE="text" NAME="city" SIZE=32 VALUE="$hashref->{city}"> +State <INPUT TYPE="text" NAME="state" SIZE=16 MAXLENGTH=16 VALUE="$hashref->{state}"> +Area Code <INPUT TYPE="text" NAME="ac" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{ac}"> +Exchange <INPUT TYPE="text" NAME="exch" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{exch}"> +Local <INPUT TYPE="text" NAME="loc" SIZE=5 MAXLENGTH=4 VALUE="$hashref->{loc}"> +</PRE> +END + +print qq!<BR><INPUT TYPE="submit" VALUE="!, + $hashref->{popnum} ? "Apply changes" : "Add Access Number", + qq!">!; + +print <<END; + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi new file mode 100644 index 000000000..9e064c5c8 --- /dev/null +++ b/httemplate/edit/svc_broadband.cgi @@ -0,0 +1,175 @@ +<!-- mason kludge --> +<% + +# If it's stupid but it works, it's still stupid. +# -Kristian + + +use HTML::Widgets::SelectLayers; +use Tie::IxHash; + +my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_broadband ); +if ( $cgi->param('error') ) { + $svc_broadband = new FS::svc_broadband ( { + map { $_, scalar($cgi->param($_)) } fields('svc_broadband'), qw(svcpart) + } ); + $svcnum = $svc_broadband->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $svc_broadband->svcpart; + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; +} else { + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_broadband=qsearchs('svc_broadband',{'svcnum'=>$svcnum}) + or die "Unknown (svc_broadband) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + } else { #adding + + foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + $svc_broadband = new FS::svc_broadband({ svcpart => $svcpart }); + + $svcnum=''; + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + $svc_broadband->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + + } +} +my $action = $svc_broadband->svcnum ? 'Edit' : 'Add'; + +if ($pkgnum) { + + #Nothing? + +} elsif ( $action eq 'Edit' ) { + + #Nothing? + +} else { + die "\$action eq Add, but \$pkgnum is null!\n"; +} + +my $p1 = popurl(1); + +my ($ip_addr, $speed_up, $speed_down, $blocknum) = + ($svc_broadband->ip_addr, + $svc_broadband->speed_up, + $svc_broadband->speed_down, + $svc_broadband->blocknum); + +%> + +<%=header("Broadband Service $action", '')%> + +<% if ($cgi->param('error')) { %> +<FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT><BR> +<% } %> + +Service #<B><%=$svcnum ? $svcnum : "(NEW)"%></B><BR><BR> + +<FORM ACTION="<%=${p1}%>process/svc_broadband.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>"> + <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%=$pkgnum%>"> + <INPUT TYPE="hidden" NAME="svcpart" VALUE="<%=$svcpart%>"> + + <%=&ntable("#cccccc",2)%> + <TR> + <TD ALIGN="right">IP Address</TD> + <TD BGCOLOR="#ffffff"> +<% if ( $part_svc->part_svc_column('ip_addr')->columnflag eq 'F' ) { %> + <INPUT TYPE="hidden" NAME="ip_addr" VALUE="<%=$ip_addr%>"><%=$ip_addr%> +<% } else { %> + <INPUT TYPE="text" NAME="ip_addr" VALUE="<%=$ip_addr%>"> +<% } %> + </TD> + </TR> + <TR> + <TD ALIGN="right">Download speed</TD> + <TD BGCOLOR="#ffffff"> +<% if ( $part_svc->part_svc_column('speed_down')->columnflag eq 'F' ) { %> + <INPUT TYPE="hidden" NAME="speed_down" VALUE="<%=$speed_down%>"><%=$speed_down%>Kbps +<% } else { %> + <INPUT TYPE="text" NAME="speed_down" SIZE=5 VALUE="<%=$speed_down%>">Kbps +<% } %> + </TD> + </TR> + <TR> + <TD ALIGN="right">Upload speed</TD> + <TD BGCOLOR="#ffffff"> +<% if ( $part_svc->part_svc_column('speed_up')->columnflag eq 'F' ) { %> + <INPUT TYPE="hidden" NAME="speed_up" VALUE="<%=$speed_up%>"><%=$speed_up%>Kbps +<% } else { %> + <INPUT TYPE="text" NAME="speed_up" SIZE=5 VALUE="<%=$speed_up%>">Kbps +<% } %> + </TD> + </TR> +<% if ($action eq 'Add') { %> + <TR> + <TD ALIGN="right">Router/Block</TD> + <TD BGCOLOR="#ffffff"> + <SELECT NAME="blocknum"> +<% + warn $svc_broadband->svcpart; + foreach my $router ($svc_broadband->allowed_routers) { + warn $router->routername; + foreach my $addr_block ($router->addr_block) { +%> + <OPTION VALUE="<%=$addr_block->blocknum%>"<%=($addr_block->blocknum eq $blocknum) ? ' SELECTED' : ''%>> + <%=$router->routername%>:<%=$addr_block->ip_gateway%>/<%=$addr_block->ip_netmask%></OPTION> +<% + } + } +%> + </SELECT> + </TD> + </TR> +<% } else { %> + + <TR> + <TD ALIGN="right">Router/Block</TD> + <TD BGCOLOR="#ffffff"> + <%=$svc_broadband->addr_block->router->routername%>:<%=$svc_broadband->addr_block->NetAddr%> + <INPUT TYPE="hidden" NAME="blocknum" VALUE="<%=$svc_broadband->blocknum%>"> + </TD> + </TR> + +<% } %> + +<% +foreach my $field ($svc_broadband->virtual_fields) { + if ( $part_svc->part_svc_column($field)->columnflag ne 'F' && + $part_svc->part_svc_column($field)->columnflag ne 'X') { + print $svc_broadband->pvf($field)->widget('HTML', 'edit', + $svc_broadband->getfield($field)); + } +} %> + </TABLE> + <BR> + <INPUT TYPE="submit" NAME="submit" VALUE="Submit"> +</FORM> +</BODY> +</HTML> + diff --git a/httemplate/edit/svc_domain.cgi b/httemplate/edit/svc_domain.cgi new file mode 100755 index 000000000..ca0e3398f --- /dev/null +++ b/httemplate/edit/svc_domain.cgi @@ -0,0 +1,98 @@ +<!-- mason kludge --> +<% + +my($svcnum, $pkgnum, $svcpart, $kludge_action, $purpose, $part_svc, + $svc_domain); +if ( $cgi->param('error') ) { + $svc_domain = new FS::svc_domain ( { + map { $_, scalar($cgi->param($_)) } fields('svc_domain') + } ); + $svcnum = $svc_domain->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $kludge_action = $cgi->param('action'); + $purpose = $cgi->param('purpose'); + $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } ); + die "No part_svc entry!" unless $part_svc; +} else { + $kludge_action = ''; + $purpose = ''; + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum}) + or die "Unknown (svc_domain) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + } else { #adding + + $svc_domain = new FS::svc_domain({}); + + foreach $_ (split(/-/,$query)) { + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + $svcnum=''; + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + $svc_domain->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + + } + +} +my $action = $svcnum ? 'Edit' : 'Add'; + +my $svc = $part_svc->getfield('svc'); + +my $otaker = getotaker; + +my $domain = $svc_domain->domain; + +my $p1 = popurl(1); +print header("$action $svc", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print <<END; + <FORM ACTION="${p1}process/svc_domain.cgi" METHOD=POST> + <INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum"> + <INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum"> + <INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart"> +END + +print qq!<INPUT TYPE="radio" NAME="action" VALUE="N"!; +print ' CHECKED' if $kludge_action eq 'N'; +print qq!>New!; +print qq!<BR><INPUT TYPE="radio" NAME="action" VALUE="M"!; +print ' CHECKED' if $kludge_action eq 'M'; +print qq!>Transfer!; + +print <<END; +<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="$domain" SIZE=28 MAXLENGTH=63> +<BR>Purpose/Description: <INPUT TYPE="text" NAME="purpose" VALUE="$purpose" SIZE=64> +<P><INPUT TYPE="submit" VALUE="Submit"> + </FORM> + </BODY> +</HTML> +END + +%> diff --git a/httemplate/edit/svc_external.cgi b/httemplate/edit/svc_external.cgi new file mode 100644 index 000000000..bcfc85e3f --- /dev/null +++ b/httemplate/edit/svc_external.cgi @@ -0,0 +1,105 @@ +<!-- mason kludge --> +<% + +my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_external ); +if ( $cgi->param('error') ) { + $svc_external = new FS::svc_external ( { + map { $_, scalar($cgi->param($_)) } fields('svc_external') + } ); + $svcnum = $svc_external->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; +} else { + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_external=qsearchs('svc_external',{'svcnum'=>$svcnum}) + or die "Unknown (svc_external) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + } else { #adding + + foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $svc_external = new FS::svc_external { svcpart => $svcpart }; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + $svcnum=''; + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + $svc_external->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + + } +} +my $action = $svc_external->svcnum ? 'Edit' : 'Add'; + +my $p1 = popurl(1); +print header("External service $action", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="${p1}process/svc_external.cgi" METHOD=POST>!; + +#display + + +#svcnum +print qq!<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">!; +print qq!Service #<B>!, $svcnum ? $svcnum : "(NEW)", "</B><BR><BR>"; + +#pkgnum +print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!; + +#svcpart +print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!; + +my($id,$title)=( + $svc_external->id, + $svc_external->title, +); + +print &ntable("#cccccc",2), + '<TR><TD ALIGN="right">External ID</TD><TD>'. + qq!<INPUT TYPE="text" NAME="id" VALUE="$id">!. + '</TD></TR>'. + '<TR><TD ALIGN="right">Title</TD><TD>'. + qq!<INPUT TYPE="text" NAME="title" VALUE="$title">!. + '</TD></TR>'; + +foreach my $field ($svc_external->virtual_fields) { + if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { + # If the flag is X, it won't even show up in $svc_acct->virtual_fields. + print $svc_external->pvf($field)->widget('HTML', 'edit', + $svc_external->getfield($field)); + } +} + +%> + +</TABLE><BR><INPUT TYPE="submit" VALUE="Submit"> + </FORM> + </BODY> +</HTML> + diff --git a/httemplate/edit/svc_forward.cgi b/httemplate/edit/svc_forward.cgi new file mode 100755 index 000000000..2b9d35ad1 --- /dev/null +++ b/httemplate/edit/svc_forward.cgi @@ -0,0 +1,177 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; + +my($svcnum, $pkgnum, $svcpart, $part_svc, $svc_forward); +if ( $cgi->param('error') ) { + $svc_forward = new FS::svc_forward ( { + map { $_, scalar($cgi->param($_)) } fields('svc_forward') + } ); + $svcnum = $svc_forward->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; +} else { + + my($query) = $cgi->keywords; + + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_forward=qsearchs('svc_forward',{'svcnum'=>$svcnum}) + or die "Unknown (svc_forward) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + } else { #adding + + $svc_forward = new FS::svc_forward({}); + + foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + $svcnum=''; + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + $svc_forward->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + } + +} +my $action = $svc_forward->svcnum ? 'Edit' : 'Add'; + +my %email; + +#starting with those currently attached +foreach my $method (qw( srcsvc_acct dstsvc_acct )) { + my $svc_acct = $svc_forward->$method(); + $email{$svc_acct->svcnum} = $svc_acct->email if $svc_acct; +} + +if ($pkgnum) { + + #find all possible user svcnums (and emails) + + #and including the rest for this customer + my($u_part_svc,@u_acct_svcparts); + foreach $u_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_acct'}) ) { + push @u_acct_svcparts,$u_part_svc->getfield('svcpart'); + } + + my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + my($custnum)=$cust_pkg->getfield('custnum'); + my($i_cust_pkg); + foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) { + my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum'); + my($acct_svcpart); + foreach $acct_svcpart (@u_acct_svcparts) { #now find the corresponding + #record(s) in cust_svc ( for this + #pkgnum ! ) + foreach my $i_cust_svc ( + qsearch( 'cust_svc', { 'pkgnum' => $cust_pkgnum, + 'svcpart' => $acct_svcpart } ) + ) { + my $svc_acct = + qsearchs( 'svc_acct', { 'svcnum' => $i_cust_svc->svcnum } ); + $email{$svc_acct->svcnum} = $svc_acct->email; + } + } + } + +} elsif ( $action eq 'Add' ) { + die "\$action eq Add, but \$pkgnum is null!\n"; +} + +my($srcsvc,$dstsvc,$dst)=( + $svc_forward->srcsvc, + $svc_forward->dstsvc, + $svc_forward->dst, +); +my $src = $svc_forward->dbdef_table->column('src') ? $svc_forward->src : ''; + +#display + +%> + +<%= header("Mail Forward $action") %> + +<% if ( $cgi->param('error') ) { %> + <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT> + <BR><BR> +<% } %> + +Service #<%= $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> +Service: <B><%= $part_svc->svc %></B><BR><BR> + +<FORM ACTION="process/svc_forward.cgi" METHOD="POST"> +<INPUT TYPE="hidden" NAME="svcnum" VALUE="<%= $svcnum %>"> +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>"> +<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $svcpart %>"> + +<SCRIPT TYPE="text/javascript"> +function srcchanged(what) { + if ( what.options[what.selectedIndex].value == 0 ) { + what.form.src.disabled = false; + what.form.src.style.backgroundColor = "white"; + } else { + what.form.src.disabled = true; + what.form.src.style.backgroundColor = "lightgrey"; + } +} +function dstchanged(what) { + if ( what.options[what.selectedIndex].value == 0 ) { + what.form.dst.disabled = false; + what.form.dst.style.backgroundColor = "white"; + } else { + what.form.dst.disabled = true; + what.form.dst.style.backgroundColor = "lightgrey"; + } +} +</SCRIPT> + +<%= ntable("#cccccc",2) %> +<TR><TD ALIGN="right">Email to</TD> +<TD><SELECT NAME="srcsvc" SIZE=1 onChange="srcchanged(this)"> +<% foreach $_ (keys %email) { %> + <OPTION<%= $_ eq $srcsvc ? " SELECTED" : "" %> VALUE="<%= $_ %>"><%= $email{$_} %></OPTION> +<% } %> +<% if ( $svc_forward->dbdef_table->column('src') ) { %> + <OPTION <%= $src ? 'SELECTED' : '' %> VALUE="0">(other email address)</OPTION> +<% } %> +</SELECT> +<% if ( $svc_forward->dbdef_table->column('src') ) { %> +<INPUT TYPE="text" NAME="src" VALUE="<%= $src %>" <%= ( $src || !scalar(%email) ) ? '' : 'DISABLED STYLE="background-color: lightgrey"' %>> +<% } %> +</TD></TR> + +<TR><TD ALIGN="right">Forwards to</TD> +<TD><SELECT NAME="dstsvc" SIZE=1 onChange="dstchanged(this)"> +<% foreach $_ (keys %email) { %> + <OPTION<%= $_ eq $dstsvc ? " SELECTED" : "" %> VALUE="<%= $_ %>"><%= $email{$_} %></OPTION> +<% } %> +<OPTION <%= $dst ? 'SELECTED' : '' %> VALUE="0">(other email address)</OPTION> +</SELECT> +<INPUT TYPE="text" NAME="dst" VALUE="<%= $dst %>" <%= ( $dst || !scalar(%email) ) ? '' : 'DISABLED STYLE="background-color: lightgrey"' %>> +</TD></TR> + </TABLE> +<BR><INPUT TYPE="submit" VALUE="Submit"> +</FORM> + </BODY> +</HTML> diff --git a/httemplate/edit/svc_www.cgi b/httemplate/edit/svc_www.cgi new file mode 100644 index 000000000..4989bb610 --- /dev/null +++ b/httemplate/edit/svc_www.cgi @@ -0,0 +1,221 @@ +<!-- mason kludge --> +<% + +my $conf = new FS::Conf; + +my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_www ); +if ( $cgi->param('error') ) { + $svc_www = new FS::svc_www ( { + map { $_, scalar($cgi->param($_)) } fields('svc_www') + } ); + $svcnum = $svc_www->svcnum; + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; +} else { + my($query) = $cgi->keywords; + if ( $query =~ /^(\d+)$/ ) { #editing + $svcnum=$1; + $svc_www=qsearchs('svc_www',{'svcnum'=>$svcnum}) + or die "Unknown (svc_www) svcnum!"; + + my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum}) + or die "Unknown (cust_svc) svcnum!"; + + $pkgnum=$cust_svc->pkgnum; + $svcpart=$cust_svc->svcpart; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + } else { #adding + + foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart + $pkgnum=$1 if /^pkgnum(\d+)$/; + $svcpart=$1 if /^svcpart(\d+)$/; + } + $svc_www = new FS::svc_www { svcpart => $svcpart }; + + $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart}); + die "No part_svc entry!" unless $part_svc; + + $svcnum=''; + + #set fixed and default fields from part_svc + foreach my $part_svc_column ( + grep { $_->columnflag } $part_svc->all_part_svc_column + ) { + $svc_www->setfield( $part_svc_column->columnname, + $part_svc_column->columnvalue, + ); + } + + } +} +my $action = $svc_www->svcnum ? 'Edit' : 'Add'; + +my( %svc_acct, %arec ); +if ($pkgnum) { + + my @u_acct_svcparts; + foreach my $svcpart ( + map { $_->svcpart } qsearch( 'part_svc', { 'svcdb' => 'svc_acct' } ) + ) { + next if $conf->exists('svc_www-usersvc_svcpart') + && ! grep { $svcpart == $_ } + $conf->config('svc_www-usersvc_svcpart'); + push @u_acct_svcparts, $svcpart; + } + + my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + my($custnum)=$cust_pkg->getfield('custnum'); + my($i_cust_pkg); + foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) { + my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum'); + my($acct_svcpart); + foreach $acct_svcpart (@u_acct_svcparts) { #now find the corresponding + #record(s) in cust_svc ( for this + #pkgnum ! ) + my($i_cust_svc); + foreach $i_cust_svc ( qsearch('cust_svc',{'pkgnum'=>$cust_pkgnum,'svcpart'=>$acct_svcpart}) ) { + my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$i_cust_svc->getfield('svcnum')}); + $svc_acct{$svc_acct->getfield('svcnum')}= + $svc_acct->cust_svc->part_svc->svc. ': '. $svc_acct->email; + } + } + } + + + my($d_part_svc,@d_acct_svcparts); + foreach $d_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_domain'}) ) { + push @d_acct_svcparts,$d_part_svc->getfield('svcpart'); + } + + foreach $i_cust_pkg ( qsearch( 'cust_pkg', { 'custnum' => $custnum } ) ) { + my $cust_pkgnum = $i_cust_pkg->pkgnum; + + foreach my $acct_svcpart (@d_acct_svcparts) { + + foreach my $i_cust_svc ( + qsearch( 'cust_svc', { 'pkgnum' => $cust_pkgnum, + 'svcpart' => $acct_svcpart } ) + ) { + my $svc_domain = + qsearchs( 'svc_domain', { 'svcnum' => $i_cust_svc->svcnum } ); + + my $extra_sql = "AND ( rectype = 'A' OR rectype = 'CNAME' )"; + unless ( $conf->exists('svc_www-enable_subdomains') ) { + $extra_sql .= " AND ( reczone = '\@' OR reczone = '". + $svc_domain->domain. ".' )"; + } + + foreach my $domain_rec ( + qsearch( 'domain_record', + { + 'svcnum' => $svc_domain->svcnum, + }, + '', + $extra_sql, + ) + ) { + $arec{$domain_rec->recnum} = $domain_rec->zone; + } + + if ( $conf->exists('svc_www-enable_subdomains') ) { + $arec{'www.'. $svc_domain->domain} = 'www.'. $svc_domain->domain + unless qsearchs( 'domain_record', { + svcnum => $svc_domain->svcnum, + reczone => 'www', + } ) + || qsearchs( 'domain_record', { + svcnum => $svc_domain->svcnum, + reczone => 'www.'.$svc-domain->domain.'.', + } ); + } + + $arec{'@.'. $svc_domain->domain} = $svc_domain->domain + unless qsearchs('domain_record', { + svcnum => $svc_domain->svcnum, + reczone => '@', + } ) + || qsearchs('domain_record', { + svcnum => $svc_domain->svcnum, + reczone => $svc_domain->domain.'.', + } ); + + } + + } + } + +} elsif ( $action eq 'Edit' ) { + + my($domain_rec) = qsearchs('domain_record', { 'recnum'=>$svc_www->recnum }); + $arec{$svc_www->recnum} = join '.', $domain_rec->recdata, $domain_rec->reczone; + +} else { + die "\$action eq Add, but \$pkgnum is null!\n"; +} + + +my $p1 = popurl(1); +print header("Web Hosting $action", ''); + +print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'), + "</FONT>" + if $cgi->param('error'); + +print qq!<FORM ACTION="${p1}process/svc_www.cgi" METHOD=POST>!; + +#display + + + +#svcnum +print qq!<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">!; +print qq!Service #<B>!, $svcnum ? $svcnum : "(NEW)", "</B><BR><BR>"; + +#pkgnum +print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!; + +#svcpart +print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!; + +my($recnum,$usersvc)=( + $svc_www->recnum, + $svc_www->usersvc, +); + +print &ntable("#cccccc",2), + '<TR><TD ALIGN="right">Zone</TD><TD><SELECT NAME="recnum" SIZE=1>'; +foreach $_ (keys %arec) { + print "<OPTION", $_ eq $recnum ? " SELECTED" : "", + qq! VALUE="$_">$arec{$_}!; +} +print "</SELECT></TD></TR>"; + +print '<TR><TD ALIGN="right">Username</TD><TD><SELECT NAME="usersvc" SIZE=1>'; +foreach $_ (keys %svc_acct) { + print "<OPTION", ($_ eq $usersvc) ? " SELECTED" : "", + qq! VALUE="$_">$svc_acct{$_}!; +} +print "</SELECT></TD></TR>"; + +foreach my $field ($svc_www->virtual_fields) { + if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { + # If the flag is X, it won't even show up in $svc_acct->virtual_fields. + print $svc_www->pvf($field)->widget('HTML', 'edit', + $svc_www->getfield($field)); + } +} + +print '</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">'; + +print <<END; + + </FORM> + </BODY> +</HTML> +END +%> |