diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-01-18 19:43:48 -0800 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-01-18 19:43:48 -0800 |
commit | f92a083465019a7224d912cd78b6881f8aef1b52 (patch) | |
tree | 4816e5b52373ebaf62681e19bec8ed304f99f5e6 | |
parent | 03c12b4dabfcaabc218f39ee13557edebc13931d (diff) |
one-time charges on quotations, RT#25561
-rw-r--r-- | FS/FS/quotation.pm | 130 | ||||
-rw-r--r-- | httemplate/edit/process/quick-charge.cgi | 71 | ||||
-rw-r--r-- | httemplate/edit/quick-charge.html | 155 | ||||
-rw-r--r-- | httemplate/elements/one_time_charge_link.html (renamed from httemplate/view/cust_main/one_time_charge_link.html) | 29 | ||||
-rwxr-xr-x | httemplate/view/cust_main/packages.html | 2 | ||||
-rwxr-xr-x | httemplate/view/quotation.html | 8 |
6 files changed, 293 insertions, 102 deletions
diff --git a/FS/FS/quotation.pm b/FS/FS/quotation.pm index 44b72f4..75a592d 100644 --- a/FS/FS/quotation.pm +++ b/FS/FS/quotation.pm @@ -7,8 +7,11 @@ use Tie::RefHash; use FS::CurrentUser; use FS::UID qw( dbh ); use FS::Maketext qw( emt ); +use FS::Record qw( qsearchs ); use FS::cust_main; use FS::cust_pkg; +use FS::quotation_pkg; +use FS::type_pkgs; =head1 NAME @@ -351,6 +354,133 @@ sub order { } +=item charge + +One-time charges, like FS::cust_main::charge() + +=cut + +#super false laziness w/cust_main::charge +sub charge { + my $self = shift; + my ( $amount, $setup_cost, $quantity, $start_date, $classnum ); + my ( $pkg, $comment, $additional ); + my ( $setuptax, $taxclass ); #internal taxes + my ( $taxproduct, $override ); #vendor (CCH) taxes + my $no_auto = ''; + my $cust_pkg_ref = ''; + my ( $bill_now, $invoice_terms ) = ( 0, '' ); + my $locationnum; + if ( ref( $_[0] ) ) { + $amount = $_[0]->{amount}; + $setup_cost = $_[0]->{setup_cost}; + $quantity = exists($_[0]->{quantity}) ? $_[0]->{quantity} : 1; + $start_date = exists($_[0]->{start_date}) ? $_[0]->{start_date} : ''; + $no_auto = exists($_[0]->{no_auto}) ? $_[0]->{no_auto} : ''; + $pkg = exists($_[0]->{pkg}) ? $_[0]->{pkg} : 'One-time charge'; + $comment = exists($_[0]->{comment}) ? $_[0]->{comment} + : '$'. sprintf("%.2f",$amount); + $setuptax = exists($_[0]->{setuptax}) ? $_[0]->{setuptax} : ''; + $taxclass = exists($_[0]->{taxclass}) ? $_[0]->{taxclass} : ''; + $classnum = exists($_[0]->{classnum}) ? $_[0]->{classnum} : ''; + $additional = $_[0]->{additional} || []; + $taxproduct = $_[0]->{taxproductnum}; + $override = { '' => $_[0]->{tax_override} }; + $cust_pkg_ref = exists($_[0]->{cust_pkg_ref}) ? $_[0]->{cust_pkg_ref} : ''; + $bill_now = exists($_[0]->{bill_now}) ? $_[0]->{bill_now} : ''; + $invoice_terms = exists($_[0]->{invoice_terms}) ? $_[0]->{invoice_terms} : ''; + $locationnum = $_[0]->{locationnum} || $self->ship_locationnum; + } else { + $amount = shift; + $setup_cost = ''; + $quantity = 1; + $start_date = ''; + $pkg = @_ ? shift : 'One-time charge'; + $comment = @_ ? shift : '$'. sprintf("%.2f",$amount); + $setuptax = ''; + $taxclass = @_ ? shift : ''; + $additional = []; + } + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $part_pkg = new FS::part_pkg ( { + 'pkg' => $pkg, + 'comment' => $comment, + 'plan' => 'flat', + 'freq' => 0, + 'disabled' => 'Y', + 'classnum' => ( $classnum ? $classnum : '' ), + 'setuptax' => $setuptax, + 'taxclass' => $taxclass, + 'taxproductnum' => $taxproduct, + 'setup_cost' => $setup_cost, + } ); + + my %options = ( ( map { ("additional_info$_" => $additional->[$_] ) } + ( 0 .. @$additional - 1 ) + ), + 'additional_count' => scalar(@$additional), + 'setup_fee' => $amount, + ); + + my $error = $part_pkg->insert( options => \%options, + tax_overrides => $override, + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + my $pkgpart = $part_pkg->pkgpart; + + #DIFF + my %type_pkgs = ( 'typenum' => $self->cust_or_prospect->agent->typenum, 'pkgpart' => $pkgpart ); + + unless ( qsearchs('type_pkgs', \%type_pkgs ) ) { + my $type_pkgs = new FS::type_pkgs \%type_pkgs; + $error = $type_pkgs->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + #except for DIFF, eveything above is idential to cust_main version + #but below is our own thing pretty much (adding a quotation package instead + # of ordering a customer package, no "bill now") + + my $quotation_pkg = new FS::quotation_pkg ( { + 'quotationnum' => $self->quotationnum, + 'pkgpart' => $pkgpart, + 'quantity' => $quantity, + #'start_date' => $start_date, + #'no_auto' => $no_auto, + 'locationnum'=> $locationnum, + } ); + + $error = $quotation_pkg->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + #} elsif ( $cust_pkg_ref ) { + # ${$cust_pkg_ref} = $cust_pkg; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; + +} + =item disable Disables this quotation (sets disabled to Y, which hides the quotation on diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi index 6de746e..c130a55 100644 --- a/httemplate/edit/process/quick-charge.cgi +++ b/httemplate/edit/process/quick-charge.cgi @@ -24,15 +24,20 @@ for ( my $row = 0; exists($param->{"description$row"}); $row++ ) { if ($param->{"description$row"} =~ /\S/); } -$param->{"custnum"} =~ /^(\d+)$/ - or $error .= "Illegal customer number " . $param->{"custnum"} . " "; -my $custnum = $1; - -my $cust_main = FS::cust_main->by_key($custnum) - or die "custnum $custnum not found"; - -exists($curuser->agentnums_href->{$cust_main->agentnum}) - or die "access denied"; +my( $cust_main, $prospect_main, $quotation ) = ( '', '', '' ); +if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) { + $quotation = FS::quotation->by_key($1) or die "quotationnum $1 not found"; +} +if ( $param->{"custnum"} =~ /^(\d+)$/ ) { + $cust_main = FS::cust_main->by_key($1) or die "custnum $1 not found"; + exists($curuser->agentnums_href->{$cust_main->agentnum}) + or die "access denied"; +} +if ( $param->{"prospectnum"} =~ /^(\d+)$/ ) { + $prospect_main = FS::prospect_main->by_key($1) or die "prospectnum $1 not found"; + exists($curuser->agentnums_href->{$prospect_main->agentnum}) + or die "access denied"; +} my $message; @@ -106,30 +111,32 @@ if ( $param->{'pkgnum'} =~ /^(\d+)$/ ) { #modifying an existing one-time charge $cgi->param('taxclass', ''); } - unless ( $error ) { - my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) - or $error .= "Unknown customer number $custnum. "; - - $error ||= $cust_main->charge( { - 'amount' => $amount, - 'setup_cost' => $setup_cost, - 'quantity' => $quantity, - 'bill_now' => scalar($cgi->param('bill_now')), - 'invoice_terms' => scalar($cgi->param('invoice_terms')), - 'start_date' => ( scalar($cgi->param('start_date')) - ? parse_datetime($cgi->param('start_date')) - : '' - ), - 'no_auto' => scalar($cgi->param('no_auto')), - 'pkg' => scalar($cgi->param('pkg')), - 'setuptax' => scalar($cgi->param('setuptax')), - 'taxclass' => scalar($cgi->param('taxclass')), - 'taxproductnum' => scalar($cgi->param('taxproductnum')), - 'tax_override' => $override, - 'classnum' => scalar($cgi->param('classnum')), - 'additional' => \@description, - } ); + my %charge = ( + 'amount' => $amount, + 'setup_cost' => $setup_cost, + 'quantity' => $quantity, + 'bill_now' => scalar($cgi->param('bill_now')), + 'invoice_terms' => scalar($cgi->param('invoice_terms')), + 'start_date' => ( scalar($cgi->param('start_date')) + ? parse_datetime($cgi->param('start_date')) + : '' + ), + 'no_auto' => scalar($cgi->param('no_auto')), + 'pkg' => scalar($cgi->param('pkg')), + 'setuptax' => scalar($cgi->param('setuptax')), + 'taxclass' => scalar($cgi->param('taxclass')), + 'taxproductnum' => scalar($cgi->param('taxproductnum')), + 'tax_override' => $override, + 'classnum' => scalar($cgi->param('classnum')), + 'additional' => \@description, + ); + + if ( $quotation ) { + $error ||= $quotation->charge( \%charge ); + } else { + $error ||= $cust_main->charge( \%charge ); } + } </%init> diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html index ec1a580..dfaf404 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -100,7 +100,9 @@ function bill_now_changed (what) { onSubmit = "document.QuickChargeForm.submit.disabled=true; return validate_quick_charge();" > -<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $cust_main ? $cust_main->custnum : '' %>"> +<INPUT TYPE="hidden" NAME="prospectnum" VALUE="<% $prospect_main ? $prospect_main->prospectnum : '' %>"> +<INPUT TYPE="hidden" NAME="quotationnum" VALUE="<% $quotationnum %>"> <TABLE ID="QuickChargeTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 STYLE="background-color: #cccccc"> @@ -209,63 +211,67 @@ function bill_now_changed (what) { <& /elements/tr-select-pkg_class.html, 'curr_value' => $classnum &> -<TR> - <TD ALIGN="right"><% mt('Invoice now') |h %></TD> - <TD> - <INPUT TYPE = "checkbox" - NAME = "bill_now" - VALUE = "1" - <% $cgi->param('bill_now') ? 'CHECKED' : '' %> - onClick = "bill_now_changed(this);" - onChange = "bill_now_changed(this);" - > - <% mt('with terms') |h %> - <& /elements/select-terms.html, - 'curr_value' => scalar($cgi->param('invoice_terms')), - 'disabled' => ( $cgi->param('bill_now') ? 0 : 1 ), - 'agentnum' => $cust_main->agentnum, - &> - </TD> -</TR> +% unless ( $quotationnum ) { -%# false laziness w/misc/order_pkg.html -<TR> - <TD ALIGN="right"><% mt('Charge date') |h %> </TD> - <TD> - <INPUT TYPE = "text" - NAME = "start_date" - SIZE = 32 - ID = "start_date_text" - VALUE = "<% $start_date %>" - onKeyPress="return enable_quick_charge(event)" - <% $cgi->param('bill_now') - ? 'STYLE = "background-color:#dddddd" DISABLED' - : '' - %> - > - <IMG SRC = "<%$fsurl%>images/calendar.png" - ID = "start_date_button" - TITLE = "<% mt('Select date') |h %>" - STYLE = "cursor:pointer<% $cgi->param('bill_now') ? ';display:none' : '' %>" - > - <IMG SRC = "<%$fsurl%>images/calendar-disabled.png" - ID = "start_date_button_disabled" - <% $cgi->param('bill_now') ? '' : 'STYLE="display:none"' %> - > - <FONT SIZE=-1>(<% mt('leave blank to charge immediately') |h %>)</FONT> - </TD> -</TR> + <TR> + <TD ALIGN="right"><% mt('Invoice now') |h %></TD> + <TD> + <INPUT TYPE = "checkbox" + NAME = "bill_now" + VALUE = "1" + <% $cgi->param('bill_now') ? 'CHECKED' : '' %> + onClick = "bill_now_changed(this);" + onChange = "bill_now_changed(this);" + > + <% mt('with terms') |h %> + <& /elements/select-terms.html, + 'curr_value' => scalar($cgi->param('invoice_terms')), + 'disabled' => ( $cgi->param('bill_now') ? 0 : 1 ), + 'agentnum' => $cust_or_prospect->agentnum, + &> + </TD> + </TR> -<SCRIPT TYPE="text/javascript"> - Calendar.setup({ - inputField: "start_date_text", - ifFormat: "<% $date_format %>", - button: "start_date_button", - align: "BR" - }); -</SCRIPT> +% # false laziness w/misc/order_pkg.html + <TR> + <TD ALIGN="right"><% mt('Charge date') |h %> </TD> + <TD> + <INPUT TYPE = "text" + NAME = "start_date" + SIZE = 32 + ID = "start_date_text" + VALUE = "<% $start_date %>" + onKeyPress="return enable_quick_charge(event)" + <% $cgi->param('bill_now') + ? 'STYLE = "background-color:#dddddd" DISABLED' + : '' + %> + > + <IMG SRC = "<%$fsurl%>images/calendar.png" + ID = "start_date_button" + TITLE = "<% mt('Select date') |h %>" + STYLE = "cursor:pointer<% $cgi->param('bill_now') ? ';display:none' : '' %>" + > + <IMG SRC = "<%$fsurl%>images/calendar-disabled.png" + ID = "start_date_button_disabled" + <% $cgi->param('bill_now') ? '' : 'STYLE="display:none"' %> + > + <FONT SIZE=-1>(<% mt('leave blank to charge immediately') |h %>)</FONT> + </TD> + </TR> + + <SCRIPT TYPE="text/javascript"> + Calendar.setup({ + inputField: "start_date_text", + ifFormat: "<% $date_format %>", + button: "start_date_button", + align: "BR" + }); + </SCRIPT> -% if ( $cust_main->payby =~ /^(CARD|CHEK)$/ ) { +% } + +% if ( ! $quotationnum && $cust_main->payby =~ /^(CARD|CHEK)$/ ) { % my $what = lc(FS::payby->shortname($cust_main->payby)); <TR> <TD ALIGN="right"><% mt("Disable automatic $what charge") |h %> </TD> @@ -409,7 +415,7 @@ my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $money_char = $conf->config('money_char') || '$'; -my ($cust_main, $cust_pkg); +my( $cust_main, $cust_pkg, $prospect_main, $quotationnum ) = ( '', '', '', '' ); if ( $cgi->param('change_pkgnum') ) { # change an existing one-time charge die "access denied" @@ -419,18 +425,37 @@ if ( $cgi->param('change_pkgnum') ) { $cust_pkg = FS::cust_pkg->by_key($1) or die "pkgnum $1 not found"; $cust_main = $cust_pkg->cust_main; } else { - $cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; - $cust_main = FS::cust_main->by_key($1) or die "custnum $1 not found"; + if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) { + $quotationnum = $1; + } + if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + $cust_main = FS::cust_main->by_key($1) or die "custnum $1 not found"; + } + if ( $cgi->param('prospectnum') =~ /^(\d+)$/ ) { + $prospect_main = FS::prospect_main->by_key($1) or die "prospectnum $1 not found"; + } + die "custnum or prospectnum must be specified" + unless $cust_main || $prospect_main; } -my $custnum = $cust_main->custnum; -# agent-virt -if (!exists($curuser->agentnums_href->{$cust_main->agentnum})) { - die "custnum $custnum not found"; +my $cust_or_prospect = $cust_main || $prospect_main; + +if ( $cust_main ) { + my $custnum = $cust_main->custnum; + # agent-virt + if (!exists($curuser->agentnums_href->{$cust_main->agentnum})) { + die "custnum $custnum not found"; + } +} elsif ( $prospect_main ) { + my $prospectnum = $prospect_main->prospectnum; + # agent-virt + if (!exists($curuser->agentnums_href->{$prospect_main->agentnum})) { + die "prospectnum $prospectnum not found"; + } } my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi? -my $start_date = $cust_main->next_bill_date; +my $start_date = $cust_main ? $cust_main->next_bill_date : ''; $start_date = $start_date ? time2str($format, $start_date) : ''; my $amount = ''; @@ -453,12 +478,12 @@ $cgi->param('pkg') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ my $pkg = $1; my $default_terms; -if ( $cust_main->invoice_terms ) { +if ( $cust_main && $cust_main->invoice_terms ) { $default_terms = emt("Customer default ([_1])", $cust_main->invoice_terms); } else { $default_terms = emt( "Default ([_1])", - ( $conf->config('invoice_default_terms', $cust_main->agentnum) + ( $conf->config('invoice_default_terms', $cust_or_prospect->agentnum) || emt('Payable upon receipt') ) ); diff --git a/httemplate/view/cust_main/one_time_charge_link.html b/httemplate/elements/one_time_charge_link.html index 1efd2d0..4ef5ede 100644 --- a/httemplate/view/cust_main/one_time_charge_link.html +++ b/httemplate/elements/one_time_charge_link.html @@ -1,3 +1,16 @@ +<%doc> + +Example: + + <& /elements/one_time_charge_link.html, + + #one of these is required + 'custnum' => $custnum, + 'prospectnum' => $prospectnum, + + &> + +</%doc> <SCRIPT TYPE="text/javascript"> function taxproductmagic(which) { @@ -72,10 +85,16 @@ function taxoverridequickchargemagic() { </SCRIPT> -<FORM NAME='quickcharge' STYLE="margin:0; padding:0; display:inline"><INPUT NAME="taxproductnum" ID="taxproductnum" TYPE="hidden"><INPUT NAME="tax_override" ID="tax_override" TYPE="hidden"><INPUT NAME="charge_storage" ID="charge_storage" TYPE="hidden"><INPUT NAME="taxproductnum_description" ID="taxproductnum_description" TYPE="hidden"></FORM> +<FORM NAME='quickcharge' STYLE="margin:0; padding:0; display:inline"> +% for (qw( +% taxproductnum tax_override charge_storage taxproductnum_description +% )) { + <INPUT NAME="<% $_ %>" ID="<% $_ %>" TYPE="hidden"> +% } +</FORM> <% include('/elements/popup_link.html', { - 'action' => $p.'edit/quick-charge.html?custnum='. $cust_main->custnum, + 'action' => $p. 'edit/quick-charge.html?'. $query, 'label' => emt('One-time charge'), 'actionlabel' => emt('One-time charge'), 'color' => '#333399', @@ -86,6 +105,10 @@ function taxoverridequickchargemagic() { <%init> -my($cust_main) = @_; +my %opt = @_; + +my $query = $opt{custnum} ? 'custnum='.$opt{custnum} + : 'prospectnum='.$opt{prospectnum}; +$query .= ';quotationnum='.$opt{quotationnum} if $opt{quotationnum}; </%init> diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 228b04e..9a2332b 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -96,7 +96,7 @@ if ( el ) el.scrollIntoView(true); % && $conf->config('payby-default') ne 'HIDE' % ) { <% $s++ ? ' | ' : '' %> - <& one_time_charge_link.html, $cust_main &> + <& /elements/one_time_charge_link.html, 'custnum'=>$cust_main->custnum &> % } % if ( $curuser->access_right('Bulk move customer services') ) { diff --git a/httemplate/view/quotation.html b/httemplate/view/quotation.html index 81c7cdd..bd998bb 100755 --- a/httemplate/view/quotation.html +++ b/httemplate/view/quotation.html @@ -17,9 +17,15 @@ function areyousure(href, message) { 'actionlabel' => emt('Add package'), map { $_ => $quotation->$_ } qw( quotationnum custnum prospectnum ) &> - <BR><BR> % } +% if ( $curuser->access_right('One-time charge') ) { + | <& /elements/one_time_charge_link.html, + map { $_ => $quotation->$_ } qw( quotationnum custnum prospectnum ) + &> +% } + <BR><BR> + % if ( 1 ) { #if ( $curuser->access_right('Send quotations') ) <& /elements/popup_link.html, |