diff options
| author | jeff <jeff> | 2009-10-28 19:01:18 +0000 | 
|---|---|---|
| committer | jeff <jeff> | 2009-10-28 19:01:18 +0000 | 
| commit | 2cb70470a8e5c3287146008e4ce2c4eb9f242373 (patch) | |
| tree | e8d161557d4420f988245f3bf00d25d80b1d73d4 | |
| parent | 57f5975a062022e280680feed1f692f3e937414b (diff) | |
UI changes for credit applications include on the fly tax calculations #4729
| -rw-r--r-- | FS/FS/cust_bill_pkg.pm | 3 | ||||
| -rw-r--r-- | FS/FS/cust_credit.pm | 3 | ||||
| -rw-r--r-- | FS/FS/cust_main.pm | 241 | ||||
| -rw-r--r-- | httemplate/edit/elements/ApplicationCommon.html | 231 | ||||
| -rwxr-xr-x | httemplate/edit/process/cust_credit_bill.cgi | 6 | ||||
| -rw-r--r-- | httemplate/edit/process/elements/ApplicationCommon.html | 18 | 
6 files changed, 395 insertions, 107 deletions
| diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 4058f1f38..016b8bf66 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -627,7 +627,8 @@ sub disintegrate {    }    #split usage from recur -  my $usage = sprintf( "%.2f", $cust_bill_pkg{recur}->usage ); +  my $usage = sprintf( "%.2f", $cust_bill_pkg{recur}->usage ) +    if exists($cust_bill_pkg{recur});    warn "usage is $usage\n" if $DEBUG > 1;    if ($usage) {      my $cust_bill_pkg_usage = diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 6c3effa13..fda10decf 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -306,6 +306,9 @@ sub check {    return "amount must be > 0 " if $self->amount <= 0; +  return "amount must be greater or equal to amount applied" +    if $self->unapplied < 0; +    return "Unknown customer"      unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 1c6284976..700e15a79 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2623,6 +2623,141 @@ sub bill {    } +  my $listref_or_error = +    $self->calculate_taxes( \@cust_bill_pkg, \%taxlisthash, $invoice_time); + +  unless ( ref( $listref_or_error ) ) { +    $dbh->rollback if $oldAutoCommit; +    return $listref_or_error; +  } + +  foreach my $taxline ( @$listref_or_error ) { +    $total_setup = sprintf('%.2f', $total_setup+$taxline->setup ); +    push @cust_bill_pkg, $taxline; +  } + +  #add tax adjustments +  warn "adding tax adjustments...\n" if $DEBUG > 2; +  foreach my $cust_tax_adjustment ( +    qsearch('cust_tax_adjustment', { 'custnum'    => $self->custnum, +                                     'billpkgnum' => '', +                                   } +           ) +  ) { + +    my $tax = sprintf('%.2f', $cust_tax_adjustment->amount ); + +    my $itemdesc = $cust_tax_adjustment->taxname; +    $itemdesc = '' if $itemdesc eq 'Tax'; + +    push @cust_bill_pkg, new FS::cust_bill_pkg { +      'pkgnum'      => 0, +      'setup'       => $tax, +      'recur'       => 0, +      'sdate'       => '', +      'edate'       => '', +      'itemdesc'    => $itemdesc, +      'itemcomment' => $cust_tax_adjustment->comment, +      'cust_tax_adjustment' => $cust_tax_adjustment, +      #'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location, +    }; + +  } + +  my $charged = sprintf('%.2f', $total_setup + $total_recur ); + +  my @cust_bill = $self->cust_bill; +  my $balance = $self->balance; +  my $previous_balance = scalar(@cust_bill) +                           ? ( $cust_bill[$#cust_bill]->billing_balance || 0 ) +                           : 0; + +  $previous_balance += $cust_bill[$#cust_bill]->charged +    if scalar(@cust_bill); +  #my $balance_adjustments = +  #  sprintf('%.2f', $balance - $prior_prior_balance - $prior_charged); + +  #create the new invoice +  my $cust_bill = new FS::cust_bill ( { +    'custnum'             => $self->custnum, +    '_date'               => ( $invoice_time ), +    'charged'             => $charged, +    'billing_balance'     => $balance, +    'previous_balance'    => $previous_balance, +    'invoice_terms'       => $options{'invoice_terms'}, +  } ); +  $error = $cust_bill->insert; +  if ( $error ) { +    $dbh->rollback if $oldAutoCommit; +    return "can't create invoice for customer #". $self->custnum. ": $error"; +  } + +  foreach my $cust_bill_pkg ( @cust_bill_pkg ) { +    $cust_bill_pkg->invnum($cust_bill->invnum);  +    my $error = $cust_bill_pkg->insert; +    if ( $error ) { +      $dbh->rollback if $oldAutoCommit; +      return "can't create invoice line item: $error"; +    } +  } +     + +  foreach my $hook ( @precommit_hooks ) {  +    eval { +      &{$hook}; #($self) ? +    }; +    if ( $@ ) { +      $dbh->rollback if $oldAutoCommit; +      return "$@ running precommit hook $hook\n"; +    } +  } +   +  $dbh->commit or die $dbh->errstr if $oldAutoCommit; +  ''; #no error +} + +=item calculate_taxes LINEITEMREF TAXHASHREF INVOICE_TIME + +This is a weird one.  Perhaps it should not even be exposed. + +Generates tax line items (see L<FS::cust_bill_pkg>) for this customer. +Usually used internally by bill method B<bill>. + +If there is an error, returns the error, otherwise returns reference to a +list of line items suitable for insertion. + +=over 4 + +=item LINEITEMREF + +An array ref of the line items being billed. + +=item TAXHASHREF + +A strange beast.  The keys to this hash are internal identifiers consisting +of the name of the tax object type, a space, and its unique identifier ( e.g. + 'cust_main_county 23' ).  The values of the hash are listrefs.  The first +item in the list is the tax object.  The remaining items are either line +items or floating point values (currency amounts). + +The taxes are calculated on this entity.  Calculated exemption records are +transferred to the LINEITEMREF items on the assumption that they are related. + +Read the source. + +=item INVOICE_TIME + +This specifies the date appearing on the associated invoice.  Some +jurisdictions (i.e. Texas) have tax exemptions which are date sensitive. + +=back + +=cut +sub calculate_taxes { +  my ($self, $cust_bill_pkg, $taxlisthash, $invoice_time) = @_; + +  my @tax_line_items = (); +    warn "having a look at the taxes we found...\n" if $DEBUG > 2;    # keys are tax names (as printed on invoices / itemdesc ) @@ -2641,20 +2776,18 @@ sub bill {    # values are listrefs of cust_bill_pkg_tax_rate_location hashrefs    my %tax_rate_location = (); -  foreach my $tax ( keys %taxlisthash ) { -    my $tax_object = shift @{ $taxlisthash{$tax} }; +  foreach my $tax ( keys %$taxlisthash ) { +    my $tax_object = shift @{ $taxlisthash->{$tax} };      warn "found ". $tax_object->taxname. " as $tax\n" if $DEBUG > 2; -    warn " ". join('/', @{ $taxlisthash{$tax} } ). "\n" if $DEBUG > 2; +    warn " ". join('/', @{ $taxlisthash->{$tax} } ). "\n" if $DEBUG > 2;      my $hashref_or_error = -      $tax_object->taxline( $taxlisthash{$tax}, +      $tax_object->taxline( $taxlisthash->{$tax},                              'custnum'      => $self->custnum,                              'invoice_time' => $invoice_time                            ); -    unless ( ref($hashref_or_error) ) { -      $dbh->rollback if $oldAutoCommit; -      return $hashref_or_error; -    } -    unshift @{ $taxlisthash{$tax} }, $tax_object; +    return $hashref_or_error unless ref($hashref_or_error); + +    unshift @{ $taxlisthash->{$tax} }, $tax_object;      my $name   = $hashref_or_error->{'name'};      my $amount = $hashref_or_error->{'amount'}; @@ -2694,9 +2827,9 @@ sub bill {    }    #move the cust_tax_exempt_pkg records to the cust_bill_pkgs we will commit -  my %packagemap = map { $_->pkgnum => $_ } @cust_bill_pkg; -  foreach my $tax ( keys %taxlisthash ) { -    foreach ( @{ $taxlisthash{$tax} }[1 ... scalar(@{ $taxlisthash{$tax} })] ) { +  my %packagemap = map { $_->pkgnum => $_ } @$cust_bill_pkg; +  foreach my $tax ( keys %$taxlisthash ) { +    foreach ( @{ $taxlisthash->{$tax} }[1 ... scalar(@{ $taxlisthash->{$tax} })] ) {        next unless ref($_) eq 'FS::cust_bill_pkg';        push @{ $packagemap{$_->pkgnum}->_cust_tax_exempt_pkg },  @@ -2726,7 +2859,6 @@ sub bill {      next unless $tax;      $tax = sprintf('%.2f', $tax ); -    $total_setup = sprintf('%.2f', $total_setup+$tax );      my $pkg_category = qsearchs( 'pkg_category', { 'categoryname' => $taxname,                                                     'disabled'     => '', @@ -2745,7 +2877,7 @@ sub bill {      } -    push @cust_bill_pkg, new FS::cust_bill_pkg { +    push @tax_line_items, new FS::cust_bill_pkg {        'pkgnum'   => 0,        'setup'    => $tax,        'recur'    => 0, @@ -2759,88 +2891,9 @@ sub bill {    } -  #add tax adjustments -  warn "adding tax adjustments...\n" if $DEBUG > 2; -  foreach my $cust_tax_adjustment ( -    qsearch('cust_tax_adjustment', { 'custnum'    => $self->custnum, -                                     'billpkgnum' => '', -                                   } -           ) -  ) { - -    my $tax = sprintf('%.2f', $cust_tax_adjustment->amount ); -    $total_setup = sprintf('%.2f', $total_setup+$tax ); - -    my $itemdesc = $cust_tax_adjustment->taxname; -    $itemdesc = '' if $itemdesc eq 'Tax'; - -    push @cust_bill_pkg, new FS::cust_bill_pkg { -      'pkgnum'      => 0, -      'setup'       => $tax, -      'recur'       => 0, -      'sdate'       => '', -      'edate'       => '', -      'itemdesc'    => $itemdesc, -      'itemcomment' => $cust_tax_adjustment->comment, -      'cust_tax_adjustment' => $cust_tax_adjustment, -      #'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location, -    }; - -  } - -  my $charged = sprintf('%.2f', $total_setup + $total_recur ); - -  my @cust_bill = $self->cust_bill; -  my $balance = $self->balance; -  my $previous_balance = scalar(@cust_bill) -                           ? ( $cust_bill[$#cust_bill]->billing_balance || 0 ) -                           : 0; - -  $previous_balance += $cust_bill[$#cust_bill]->charged -    if scalar(@cust_bill); -  #my $balance_adjustments = -  #  sprintf('%.2f', $balance - $prior_prior_balance - $prior_charged); - -  #create the new invoice -  my $cust_bill = new FS::cust_bill ( { -    'custnum'             => $self->custnum, -    '_date'               => ( $invoice_time ), -    'charged'             => $charged, -    'billing_balance'     => $balance, -    'previous_balance'    => $previous_balance, -    'invoice_terms'       => $options{'invoice_terms'}, -  } ); -  $error = $cust_bill->insert; -  if ( $error ) { -    $dbh->rollback if $oldAutoCommit; -    return "can't create invoice for customer #". $self->custnum. ": $error"; -  } - -  foreach my $cust_bill_pkg ( @cust_bill_pkg ) { -    $cust_bill_pkg->invnum($cust_bill->invnum);  -    my $error = $cust_bill_pkg->insert; -    if ( $error ) { -      $dbh->rollback if $oldAutoCommit; -      return "can't create invoice line item: $error"; -    } -  } -     - -  foreach my $hook ( @precommit_hooks ) {  -    eval { -      &{$hook}; #($self) ? -    }; -    if ( $@ ) { -      $dbh->rollback if $oldAutoCommit; -      return "$@ running precommit hook $hook\n"; -    } -  } -   -  $dbh->commit or die $dbh->errstr if $oldAutoCommit; -  ''; #no error +  \@tax_line_items;  } -  sub _make_lines {    my ($self, %params) = @_; diff --git a/httemplate/edit/elements/ApplicationCommon.html b/httemplate/edit/elements/ApplicationCommon.html index b46a3c8fe..181430c5a 100644 --- a/httemplate/edit/elements/ApplicationCommon.html +++ b/httemplate/edit/elements/ApplicationCommon.html @@ -39,10 +39,12 @@ Examples:    )  </%doc> -<% include('/elements/header-popup.html', "Apply $src_thing$to" ) %> + +<% include('/elements/header-popup.html', "Apply $src_thing$to", '', 'onLoad="myOnLoadFunction();"') %>  <% include('/elements/error.html') %> +<P ID="ErrorMessage"></P>  <FORM ACTION="<% $p1. $opt{'form_action'} %>" NAME="ApplicationForm" ID="ApplicationForm" METHOD=POST>  <% $src_thing %> #<B><% $src_pkeyvalue %></B><BR> @@ -57,18 +59,26 @@ Examples:  <TR>    <TD ALIGN="right">Amount: </TD> -  <TD><B><% $money_char %><% $src->amount %></B></TD> +  <TD ID="original_amount"><B><% $money_char %><% $src_amount %></B> +  </TD> +  <TD> +% if ($use_sub_dst_thing && $can_change_credit) { +    <INPUT TYPE="hidden" NAME="src_amount" VALUE="<% $src_amount %>" > +    <BUTTON TYPE="button" NAME="expand_button" ID="expand_button" onClick="do_change_amount(this);">Change</BUTTON> +% } +  </TD> +  </TR>  <TR>    <TD ALIGN="right">Unapplied amount: </TD> -  <TD><B><% $money_char %><% $unapplied %></B></TD> +  <TD ID="unapplied_amount"><B><% $money_char %><% $unapplied %></B></TD>  </TR>  % if ( $src_table eq 'cust_credit' ) {      <TR>        <TD ALIGN="right">Reason: </TD> -      <TD><B><% $src->reason %></B></TD> +      <TD COLSPAN=2><B><% $src->reason %></B></TD>      </TR>  % } @@ -81,10 +91,16 @@ function changed(what) {    if ( dst == '' ) {      what.form.submit.disabled=true; +%if ($src_pkey eq 'crednum') { +    what.form.tax_button.disabled=true; +%}      return true;    }    what.form.submit.disabled=false; +%if ($src_pkey eq 'crednum') { +  what.form.tax_button.disabled=false; +%}  % foreach my $dst ( @dst ) { @@ -120,14 +136,14 @@ function changed(what) {  %             my $owed = $taxX->owed;  %             my $key = &{$key_generator}([ $cbp, 0, { $pkey => $taxX->$pkey } ]);  %             my $toapp = exists($apphash{ $key }) ? $apphash{ $key }->[1] : 0; -              <% &{$row_generator}( $cbp, $taxX->desc, $owed, $toapp, $taxX->$pkey ) %> +              <% &{$row_generator}( $key, $cbp, $taxX->desc, $owed, $toapp, $taxX->$pkey ) %>  %             $total_owed -= $owed;  %             $amount -= $toapp;  %           }  %           $desc .= ' (default)';  %         }  %         if ( $total_owed > 0 ) { -            <% &{$row_generator}($cbp, $desc, $total_owed, $amount, '') %> +            <% &{$row_generator}($key, $cbp, $desc, $total_owed, $amount, '') %>  %         }  %       }  %     } @@ -143,17 +159,156 @@ function sub_changed(what) {    var table = document.getElementById('ApplicationTable');    var i = table.rows.length;    while(i-- > 2) { -    var amount_input = table.rows[i].getElementsByTagName('input').item(0); -    amount += parseFloat( amount_input.value ) || 0;  +    var inputs = table.rows[i].getElementsByTagName('input'); +    if (! inputs.length) { +      continue; +    } +    amount += parseFloat( inputs.item(0).value ) || 0;     }    what.form.amount.value = parseFloat(amount).toFixed(2);    what.form.display_amount.value = parseFloat(amount).toFixed(2); +  set_amount_color(what);  } + +function set_amount_color(what) { +  if (what.form.src_amount.value < what.form.amount.value) { +    what.form.display_amount.style.color = '#ff0000'; +  } else { +    what.form.display_amount.style.color = '#00ff00'; +  } +} +  </SCRIPT>  Apply to: +% if ($use_sub_dst_thing && $src_pkey eq 'crednum') { +<CENTER><BUTTON TYPE="button" NAME="tax_button" ID="tax_button" onClick="do_calculate_tax(this);" DISABLED>Calculate Tax</BUTTON></CENTER> +<% include( '/elements/xmlhttp.html', +            'url' =>  $p.'misc/xmlhttp-calculate_taxes.html', +            'subs' => [ 'calculate_taxes' ], +          ) + %> +<SCRIPT TYPE="text/javascript"> + +function show_taxes(arg) { +  var argsHash = eval('(' + arg + ')'); + +  var button = document.getElementById('tax_button'); +  button.disabled = false; +  button.innerHTML = 'Calculate Tax'; + +  var error = argsHash['error']; + +  var paragraph = document.getElementById('ErrorMessage'); +  if (error) { +    paragraph.innerHTML = 'Error: ' + error; +    paragraph.style.color = '#ff0000'; +  } else { +    paragraph.innerHTML = ''; +  } +  var taxlines = argsHash['taxlines']; + +  var table = document.getElementById('ApplicationTable'); + +  var aFoundRow = 0; +  for (i = 0; taxlines[i]; i++) { +    var itemdesc = taxlines[i][0]; +    var locnum   = taxlines[i][2]; +    if (taxlines[i][3]) { +      locnum  = taxlines[i][3]; +    } + +    var found = 0; +    for (var row = 2; table.rows[row]; row++) { +      var inputs = table.rows[row].getElementsByTagName('input'); +      if (! inputs.length) { +        while ( table.rows[row] ) { +           table.deleteRow(row); +        } +        break; +      } +      if ( inputs.item(4).value == itemdesc && inputs.item(2).value == locnum ) +      { +        inputs.item(0).value = taxlines[i][1]; +        aFoundRow = found = row; +        break; +      } +    } +    if (! found) { +      var row = table.insertRow(table.rows.length); +      var warning_cell = document.createElement('TD'); +      warning_cell.style.color = '#ff0000'; +      warning_cell.colSpan = 2; +      warning_cell.innerHTML = 'Calculated Tax - ' + itemdesc + ' - ' + +                               taxlines[i][1] + ' will not be applied'; +      row.appendChild(warning_cell); +    } +  } + +  if (aFoundRow) { +    sub_changed(table.rows[aFoundRow].getElementsByTagName('input').item(0)); +  } +     +} + +function do_calculate_tax (what) { +  what.innerHTML = 'Calculating....'; +  what.disabled = true; +  var taxed_items = new Array(); +  var table = document.getElementById('ApplicationTable'); +  for (var row = 2; table.rows[row]; row++) +  { +    var inputs = table.rows[row].getElementsByTagName('input'); +    if ( !inputs.length ) { +      break; +    } +    var taxed_item = new Array( +      inputs.item(1).value, // billpkgnum +      inputs.item(3).value, // s_or_r +      inputs.item(0).value  // amount +    ); +    taxed_items.push(taxed_item); +  } + +  var args = new Array( +    'crednum', '<% $src_pkeyvalue %>', +    'items', taxed_items +  ); +  calculate_taxes ( args, show_taxes ); +} + +function do_change_amount (what) { +  var amount_cell = document.getElementById('original_amount'); +  var inputs = amount_cell.getElementsByTagName('input'); +  if (inputs.length) { +    amount_cell.innerHTML = '<B><% $money_char %></B>' + inputs.item(0).value; +  } else { +    amount_cell.innerHTML = '<% $money_char %>'; +    var amount_input = document.createElement('INPUT'); +    amount_input.setAttribute('name', 'entered_amount'); +    amount_input.setAttribute('id',   'entered_amount'); +    amount_input.style.textAlign = 'right'; +    amount_input.setAttribute('size', 8); +    amount_input.setAttribute('maxlength', 8); +    amount_input.setAttribute('value', what.form.src_amount.value); +    amount_input.setAttribute('onChange', "src_amount_changed(this);"); +    amount_cell.appendChild(amount_input); +  } +} + +function src_amount_changed (what) { +  what.form.src_amount.value = what.value; +  var unapplied_cell = document.getElementById('unapplied_amount'); +  unapplied_cell.innerHTML = '<B><% $money_char %>' + what.value + '</B>'; +  set_amount_color(what); +} + +</SCRIPT> + +%} +  <TABLE ID="ApplicationTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>  <TR> @@ -173,7 +328,7 @@ Apply to:    <TD ALIGN="right">Amount: </TD>    <TD><% $money_char %><INPUT TYPE="text" NAME="<% $use_sub_dst_thing ? 'display_' : '' %>amount" VALUE="<% $amount %>" SIZE=8 MAXLENGTH=8 <% $use_sub_dst_thing ? 'DISABLED' : '' %> STYLE="text-align:right;"></TD>  % if ($use_sub_dst_thing) { -  <INPUT TYPE="hidden" NAME="amount" VALUE="<% $amount %>" > +    <INPUT TYPE="hidden" NAME="amount" VALUE="<% $amount %>" >  % }  </TR> @@ -184,6 +339,14 @@ Apply to:  </FORM> +<SCRIPT TYPE="text/javascript"> + +function myOnLoadFunction () { +  <% $onload %> +} + +</SCRIPT> +  <% include('/elements/footer.html') %>  <%init> @@ -209,13 +372,21 @@ my $use_sub_dst_thing = 0;  $use_sub_dst_thing = 1    if ( $dst_table eq 'cust_bill' && $conf->exists("${link_table}_pkg-manual") ); +my $can_change_credit = 0; +$can_change_credit = 1 +  if ( $src_table eq 'cust_credit' &&  +       $FS::CurrentUser::CurrentUser->access_right('Post credit') && +       $FS::CurrentUser::CurrentUser->access_right('Delete credit') +     ); +  my $to = $dst_table eq 'cust_refund' ? ' to Refund' : ''; -my($src_pkeyvalue, $amount, $dst_pkeyvalue); +my($src_pkeyvalue, $amount, $dst_pkeyvalue, $src_amount);  if ( $cgi->param('error') ) {    $src_pkeyvalue = $cgi->param($src_pkey);    $amount    = $cgi->param('amount');    $dst_pkeyvalue    = $cgi->param($dst_pkey); +  $src_amount = $cgi->param('src_amount');  } else {    my($query) = $cgi->keywords;    $query =~ /^(\d+)$/; @@ -231,6 +402,8 @@ my $p1 = popurl(1);  my $src = qsearchs($src_table, { $src_pkey => $src_pkeyvalue } );  die "$src_thing $src_pkeyvalue not found!" unless $src; +$src_amount = $src->amount unless $cgi->param('error'); +  my $unapplied = $src->unapplied;  my @dst = sort {    $a->_date     <=> $b->_date @@ -240,9 +413,11 @@ my @dst = sort {    $a->_date     <=> $b->_date            qsearch($dst_table, { 'custnum' => $src->custnum } );  my $row_generator = sub { -  my ($cust_bill_pkg, $desc, $owed, $amount, $taxXnum) = @_; +  my ($key, $cust_bill_pkg, $desc, $owed, $amount, $taxXnum) = @_; +  my ($num, $s_or_r, $taxlinenum) = split(':', $key);    my $id = $cust_bill_pkg->pkgnum || 'Tax';    my $billpkgnum = $cust_bill_pkg->billpkgnum; +  my $s_or_r = $cust_bill_pkg->setup > 0 ? 'setup' : 'recur';    $amount = sprintf("%.2f", $amount);    qq! @@ -277,6 +452,20 @@ my $row_generator = sub {        taxnum_input.setAttribute('rownum', rownum);        taxnum_input.setAttribute('value', "$taxXnum");        amount_cell.appendChild(taxnum_input); +      var s_or_r_input = document.createElement('INPUT'); +      s_or_r_input.setAttribute('name', 's_or_r'+rownum); +      s_or_r_input.setAttribute('id',   's_or_r'+rownum); +      s_or_r_input.setAttribute('type', 'hidden'); +      s_or_r_input.setAttribute('rownum', rownum); +      s_or_r_input.setAttribute('value', "$s_or_r"); +      amount_cell.appendChild(s_or_r_input); +      var itemdesc_input = document.createElement('INPUT'); +      itemdesc_input.setAttribute('name', 'itemdesc'+rownum); +      itemdesc_input.setAttribute('id',   'itemdesc'+rownum); +      itemdesc_input.setAttribute('type', 'hidden'); +      itemdesc_input.setAttribute('rownum', rownum); +      itemdesc_input.setAttribute('value', "$desc"); +      amount_cell.appendChild(itemdesc_input);        row.appendChild(pkg_cell);        row.appendChild(amount_cell);        rownum++; @@ -294,4 +483,24 @@ my $key_generator = sub {    join(':', $cust_bill_pkg->billpkgnum, $setup_or_recur, $taxlinenum);  }; +my $onload = 'return true;'; + +if ($cgi->param('error')) { + +  my $set_sub_amounts = +    join(';', map { "myform.subamount$_.value = ". $cgi->param("subamount$_") } +               grep { /.+/ } +               map { /^subnum(\d+)$/ ? $1 : '' } +               $cgi->param +  ); +  $set_sub_amounts &&= "$set_sub_amounts;sub_changed(myform.subamount0)"; + +  $onload = qq! +    var myform = document.getElementById('ApplicationForm'); +    changed(myform.elements['$dst_pkey']); +    $set_sub_amounts; +    return true; +  !; +} +  </%init> diff --git a/httemplate/edit/process/cust_credit_bill.cgi b/httemplate/edit/process/cust_credit_bill.cgi index c0f34ae5b..d3847dc40 100755 --- a/httemplate/edit/process/cust_credit_bill.cgi +++ b/httemplate/edit/process/cust_credit_bill.cgi @@ -10,4 +10,10 @@  die "access denied"    unless $FS::CurrentUser::CurrentUser->access_right('Apply credit'); +if ( $cgi->param('src_amount') ) { +  die "access denied" +    unless ( $FS::CurrentUser::CurrentUser->access_right('Post credit') && +           $FS::CurrentUser::CurrentUser->access_right('Delete credit') ); +} +  </%init> diff --git a/httemplate/edit/process/elements/ApplicationCommon.html b/httemplate/edit/process/elements/ApplicationCommon.html index 3cb7ae6bf..c7bdd3ea2 100644 --- a/httemplate/edit/process/elements/ApplicationCommon.html +++ b/httemplate/edit/process/elements/ApplicationCommon.html @@ -34,6 +34,8 @@ Examples:  my %opt = @_; +my $error = ''; +  my $src_thing = ucfirst($opt{'src_thing'});  my $src_table = $opt{'src_table'};  my $src_pkey = dbdef->table($src_table)->primary_key; @@ -58,6 +60,10 @@ my @subitems = map { [ $cgi->param("subnum$_"), $cgi->param("subamount$_"), $cgi  my %options = ();  $options{subitems} = \@subitems if scalar(@subitems); + +my $oldAutoCommit = $FS::UID::AutoCommit; +local $FS::UID::AutoCommit = 0; +my $dbh = dbh;  my $new;  #  $new = new FS::cust_refund ( { @@ -70,6 +76,11 @@ my $new;  #  } );  #} else { +  if ($src->amount != $cgi->param('src_amount')) { +    $src->amount($cgi->param('src_amount')); +    $error = $src->replace; +  } +    my $class = 'FS::'. $opt{link_table};    $new = $class->new( { @@ -82,6 +93,11 @@ my $new;  $options{manual} = 1; -my $error = $new->insert( %options ); +$error ||= $new->insert( %options ); +if ($error) { +  $dbh->rollback if $oldAutoCommit; +} else { +  $dbh->commit or die $dbh->errstr if $oldAutoCommit; +}  </%init> | 
