6 include('elements/ApplicationCommon.html',
7 'form_action' => 'process/cust_bill_pay.cgi',
8 'src_table' => 'cust_pay',
9 'src_thing' => 'payment',
10 'dst_table' => 'cust_bill',
11 'dst_thing' => 'invoice',
15 include('elements/ApplicationCommon.html',
16 'form_action' => 'process/cust_credit_bill.cgi',
17 'src_table' => 'cust_credit',
18 'src_thing' => 'credit',
19 'dst_table' => 'cust_bill',
20 'dst_thing' => 'invoice',
24 include('elements/ApplicationCommon.html',
25 'form_action' => 'process/cust_pay_refund.cgi',
26 'src_table' => 'cust_pay',
27 'src_thing' => 'payment',
28 'dst_table' => 'cust_refund',
29 'dst_thing' => 'refund',
33 include('elements/ApplicationCommon.html',
34 'form_action' => 'process/cust_credit_refund.cgi',
35 'src_table' => 'cust_credit',
36 'src_thing' => 'credit',
37 'dst_table' => 'cust_refund',
38 'dst_thing' => 'refund',
42 <% include('/elements/header-popup.html', "Apply $src_thing$to" ) %>
44 <% include('/elements/error.html') %>
46 <FORM ACTION="<% $p1. $opt{'form_action'} %>" NAME="ApplicationForm" ID="ApplicationForm" METHOD=POST>
48 <% $src_thing %> #<B><% $src_pkeyvalue %></B><BR>
49 <INPUT TYPE="hidden" NAME="<% $src_pkey %>" VALUE="<% $src_pkeyvalue %>">
51 <TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
54 <TD ALIGN="right">Date: </TD>
55 <TD><B><% time2str("%D", $src->_date) %></B></TD>
59 <TD ALIGN="right">Amount: </TD>
60 <TD><B><% $money_char %><% $src->amount %></B></TD>
64 <TD ALIGN="right">Unapplied amount: </TD>
65 <TD><B><% $money_char %><% $unapplied %></B></TD>
68 % if ( $src_table eq 'cust_credit' ) {
70 <TD ALIGN="right">Reason: </TD>
71 <TD><B><% $src->reason %></B></TD>
78 <SCRIPT TYPE="text/javascript">
79 function changed(what) {
80 dst = what.options[what.selectedIndex].value;
83 what.form.submit.disabled=true;
87 what.form.submit.disabled=false;
89 % foreach my $dst ( @dst ) {
91 if ( dst == <% $dst->$dst_pkey %> ) {
92 what.form.amount.value = "<% min($dst->$dst_unapplied, $unapplied) %>";
93 % if ($use_sub_dst_thing) {
94 what.form.display_amount.value = "<% min($dst->$dst_unapplied, $unapplied) %>";
97 var table = document.getElementById('ApplicationTable');
98 while(table.rows[2]) {
101 % my $app_class = "FS::$link_table";
102 % my $temp_app = $app_class->new(
103 % { $src_pkey => $src_pkeyvalue,
104 % $dst_pkey => $dst->$dst_pkey,
105 % 'amount' => min($dst->$dst_unapplied, $unapplied),
109 % my $listref_or_error = $temp_app->calculate_applications;
110 % %apphash = map { &{$key_generator}($_), $_ } @$listref_or_error
111 % if ref($listref_or_error);
112 % foreach my $cbp ( $dst->open_cust_bill_pkg ) {
113 % my $desc = $cbp->desc;
114 % my $total_owed = $cbp->owed_setup + $cbp->owed_recur;
115 % my $key = &{$key_generator}([ $cbp, 0, {} ]);
116 % my $amount = exists($apphash{ $key }) ? $apphash{ $key }->[1] : 0;
117 % unless ( $cbp->pkgnum ) {
118 % foreach my $taxX ( $cbp->cust_bill_pkg_tax_Xlocation ) {
119 % my $pkey = $taxX->primary_key;
120 % my $owed = $taxX->owed;
121 % my $key = &{$key_generator}([ $cbp, 0, { $pkey => $taxX->$pkey } ]);
122 % my $toapp = exists($apphash{ $key }) ? $apphash{ $key }->[1] : 0;
123 <% &{$row_generator}( $cbp, $taxX->desc, $owed, $toapp, $taxX->$pkey ) %>
124 % $total_owed -= $owed;
127 % $desc .= ' (default)';
129 % if ( $total_owed > 0 ) {
130 <% &{$row_generator}($cbp, $desc, $total_owed, $amount, '') %>
140 function sub_changed(what) {
143 var table = document.getElementById('ApplicationTable');
144 var i = table.rows.length;
146 var amount_input = table.rows[i].getElementsByTagName('input').item(0);
147 amount += parseFloat( amount_input.value ) || 0;
149 what.form.amount.value = parseFloat(amount).toFixed(2);
150 what.form.display_amount.value = parseFloat(amount).toFixed(2);
157 <TABLE ID="ApplicationTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
160 <TD ALIGN="right"><% $dst_thing %>: </TD>
161 <TD><SELECT NAME="<% $dst_pkey %>" SIZE=1 onChange="changed(this)">
162 <OPTION VALUE="">Select <% $dst_thing %>
164 % foreach my $dst ( @dst ) {
165 <OPTION<% $dst->$dst_pkey eq $dst_pkeyvalue ? ' SELECTED' : '' %> VALUE="<% $dst->$dst_pkey %>">#<% $dst->$dst_pkey %> - <% time2str("%D", $dst->_date) %> - $<% $dst->$dst_unapplied %>
173 <TD ALIGN="right">Amount: </TD>
174 <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>
175 % if ($use_sub_dst_thing) {
176 <INPUT TYPE="hidden" NAME="amount" VALUE="<% $amount %>" >
183 <CENTER><INPUT TYPE="submit" VALUE="Apply" NAME="submit" ID="submit" DISABLED></CENTER>
187 <% include('/elements/footer.html') %>
193 my $conf = new FS::Conf;
194 my $money_char = $conf->config('money_char') || '$';
196 my $src_thing = ucfirst($opt{'src_thing'});
197 my $src_table = $opt{'src_table'};
198 my $src_pkey = dbdef->table($src_table)->primary_key;
200 my $dst_thing = ucfirst($opt{'dst_thing'});
201 my $dst_table = $opt{'dst_table'};
202 my $dst_pkey = dbdef->table($dst_table)->primary_key;
203 my $dst_unapplied = $dst_table eq 'cust_bill' ? 'owed' : 'unapplied';
205 $opt{form_action} =~ /^process\/(.*)\./ or die "bad form action";
208 my $use_sub_dst_thing = 0;
209 $use_sub_dst_thing = 1
210 if ( $dst_table eq 'cust_bill' && $conf->exists("${link_table}_pkg-manual") );
212 my $to = $dst_table eq 'cust_refund' ? ' to Refund' : '';
214 my($src_pkeyvalue, $amount, $dst_pkeyvalue);
215 if ( $cgi->param('error') ) {
216 $src_pkeyvalue = $cgi->param($src_pkey);
217 $amount = $cgi->param('amount');
218 $dst_pkeyvalue = $cgi->param($dst_pkey);
220 my($query) = $cgi->keywords;
227 my $otaker = getotaker;
231 my $src = qsearchs($src_table, { $src_pkey => $src_pkeyvalue } );
232 die "$src_thing $src_pkeyvalue not found!" unless $src;
234 my $unapplied = $src->unapplied;
236 my @dst = sort { $a->_date <=> $b->_date
237 or $a->$dst_pkey <=> $b->$dst_pkey
239 grep { $_->$dst_unapplied != 0 }
240 qsearch($dst_table, { 'custnum' => $src->custnum } );
242 my $row_generator = sub {
243 my ($cust_bill_pkg, $desc, $owed, $amount, $taxXnum) = @_;
244 my $id = $cust_bill_pkg->pkgnum || 'Tax';
245 my $billpkgnum = $cust_bill_pkg->billpkgnum;
247 $amount = sprintf("%.2f", $amount);
249 var tablebody = document.getElementsByTagName('tbody').item(0);
250 var row = table.insertRow(rownum+2);
251 var pkg_cell = document.createElement('TD');
252 pkg_cell.style.textAlign = 'right';
253 pkg_cell.innerHTML = "$id - $desc - $owed:";
254 var amount_cell = document.createElement('TD');
255 amount_cell.innerHTML = "$money_char";
256 var amount_input = document.createElement('INPUT');
257 amount_input.setAttribute('name', 'subamount'+rownum);
258 amount_input.setAttribute('id', 'subamount'+rownum);
259 amount_input.style.textAlign = 'right';
260 amount_input.setAttribute('size', 8);
261 amount_input.setAttribute('maxlength', 8);
262 amount_input.setAttribute('rownum', rownum);
263 amount_input.setAttribute('value', "$amount");
264 amount_input.setAttribute('onChange', "sub_changed(this);");
265 amount_cell.appendChild(amount_input);
266 var subnum_input = document.createElement('INPUT');
267 subnum_input.setAttribute('name', 'subnum'+rownum);
268 subnum_input.setAttribute('id', 'subnum'+rownum);
269 subnum_input.setAttribute('type', 'hidden');
270 subnum_input.setAttribute('rownum', rownum);
271 subnum_input.setAttribute('value', "$billpkgnum");
272 amount_cell.appendChild(subnum_input);
273 var taxnum_input = document.createElement('INPUT');
274 taxnum_input.setAttribute('name', 'taxXlocationnum'+rownum);
275 taxnum_input.setAttribute('id', 'taxXlocationnum'+rownum);
276 taxnum_input.setAttribute('type', 'hidden');
277 taxnum_input.setAttribute('rownum', rownum);
278 taxnum_input.setAttribute('value', "$taxXnum");
279 amount_cell.appendChild(taxnum_input);
280 row.appendChild(pkg_cell);
281 row.appendChild(amount_cell);
286 my $key_generator = sub {
288 my ($cust_bill_pkg, $amount, $hashref) = @$listref;
289 my $setup_or_recur = $cust_bill_pkg->setup > 0 ? 'setup' : 'recur';
290 my $taxlinenum = $hashref->{billpkgtaxlocationnum} ||
291 $hashref->{billpkgtaxratelocationnum} ||
294 join(':', $cust_bill_pkg->billpkgnum, $setup_or_recur, $taxlinenum);