Merge branch 'patch-1' of https://github.com/gjones2/Freeside
[freeside.git] / httemplate / edit / credit-cust_bill_pkg.html
1 <& /elements/header-popup.html, 'Credit line items' &>
2
3 <FORM ACTION="process/credit-cust_bill_pkg.html" METHOD="POST">
4 <INPUT TYPE="hidden" NAME="crednum" VALUE="">
5 <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum |h %>">
6 <INPUT TYPE="hidden" NAME="paybatch" VALUE="">
7 <INPUT TYPE="hidden" NAME="_date" VALUE="<% time %>">
8 <table>
9
10 % my $old_invnum = 0; 
11 %# foreach my $cust_bill_pkg ( @cust_bill_pkg ) {
12 % foreach my $item ( @items ) {
13 %   my( $setuprecur, $cust_bill_pkg ) = @$item;
14
15 %   my $method = $setuprecur eq 'setup' ? 'setup' : 'recur';
16 %   my $amount = $cust_bill_pkg->$method();
17 %   my $credited = $cust_bill_pkg->credited('', '', 'setuprecur'=>$method);
18 %   $amount -= $credited;
19 %   $amount = sprintf('%.2f', $amount);
20 %   next unless $amount > 0;
21
22 %   if ( $cust_bill_pkg->invnum ne $old_invnum ) {
23       <TR><TD COLSPAN=3 BGCOLOR="#f8f8f8">&nbsp;</TD></TR>
24       <TR><TH COLSPAN=3 BGCOLOR="#f8f8f8" ALIGN="left">Invoice #<% $cust_bill_pkg->invnum %> - <% time2str($date_format, $cust_bill_pkg->cust_bill->_date) %></TD></TR>
25 %     $old_invnum = $cust_bill_pkg->invnum;
26 %   }
27
28     <TR>
29       <TD>
30         <INPUT TYPE            = "checkbox"
31                NAME            = "billpkgnum<% $cust_bill_pkg->billpkgnum.'-'. $setuprecur %>"
32                VALUE           = "<% $amount %>"
33                onClick         = "calc_total(this)"
34                data-amount     = "<% $amount %>"
35                data-billpkgnum = "<% $cust_bill_pkg->billpkgnum %>"
36                data-setuprecur = "<% $setuprecur %>"
37         >
38       </TD>
39       <TD BGCOLOR="#ffffff"><% $cust_bill_pkg->desc |h %></TD>
40 %#    show one-time/setup vs recur vs usage?
41       <TD BGCOLOR="#ffffff" ALIGN="right"><% $money_char. $amount %></TD>
42     </TR>
43
44 % }
45
46 <TR><TD COLSPAN=3 BGCOLOR="#f8f8f8">&nbsp;</TD></TR>
47 <TR>
48   <TD></TD>
49   <TD ALIGN="right">Subtotal: </TD>
50   <TD ALIGN="right" ID="subtotal_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
51 </TR>
52 <TR>
53   <TD></TD>
54   <TD ALIGN="right">Taxes: </TD>
55   <TD ALIGN="right" ID="taxtotal_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
56 </TR>
57 <TR>
58   <TD></TD>
59   <TH ALIGN="right">Total credit amount: </TD>
60   <TH ALIGN="right" ID="total_td"><% $money_char %><% sprintf('%.2f', 0) %></TD>
61 </TR>
62 <INPUT TYPE="hidden" NAME="amount" ID="total_el" VALUE="0.00">
63
64 </table>
65
66 <table>
67
68 <& /elements/tr-select-reason.html,
69               'field'          => 'reasonnum',
70               'reason_class'   => 'R',
71               #XXX reconcile both this and show_taxes wanteding to enable this
72               'control_button' => "document.getElementById('credit_button')",
73               'cgi'            => $cgi,
74 &>
75
76 <TR>
77   <TD ALIGN="right"><% mt('Additional info') |h %></TD>
78   <TD>
79     <INPUT TYPE="text" NAME="addlinfo" VALUE="<% $cgi->param('addlinfo') |h %>">
80   </TD>
81 </TR>
82
83 </table>
84
85 <BR>
86 <INPUT TYPE="submit" ID="credit_button" VALUE="Credit" DISABLED>
87
88 </FORM>
89
90 <% include( '/elements/xmlhttp.html',
91             'url' =>  $p.'misc/xmlhttp-cust_bill_pkg-calculate_taxes.html',
92             'subs' => [ 'calculate_taxes' ],
93           )
94 %>
95 <SCRIPT TYPE="text/javascript">
96
97 function show_taxes(arg) {
98   var argsHash = eval('(' + arg + ')');
99
100   //XXX add an 'ErrorMessage' section to the HTML and re-enable
101   //var error = argsHash['error'];
102
103   //var paragraph = document.getElementById('ErrorMessage');
104   //if (error) {
105   //  paragraph.innerHTML = 'Error: ' + error;
106   //  paragraph.style.color = '#ff0000';
107   //} else {
108   //  paragraph.innerHTML = '';
109   //}
110
111   var taxlines = argsHash['taxlines'];
112
113 //XXX display the tax lines? just a total will do for now
114 //
115 //  var table = document.getElementById('ApplicationTable');
116 //
117 //  var aFoundRow = 0;
118 //  for (i = 0; taxlines[i]; i++) {
119 //    var itemdesc = taxlines[i][0];
120 //    var locnum   = taxlines[i][2];
121 //    if (taxlines[i][3]) {
122 //      locnum  = taxlines[i][3];
123 //    }
124 //
125 //    var found = 0;
126 //    for (var row = 2; table.rows[row]; row++) {
127 //      var inputs = table.rows[row].getElementsByTagName('input');
128 //      if (! inputs.length) {
129 //        while ( table.rows[row] ) {
130 //           table.deleteRow(row);
131 //        }
132 //        break;
133 //      }
134 //      if ( inputs.item(4).value == itemdesc && inputs.item(2).value == locnum )
135 //      {
136 //        inputs.item(0).value = taxlines[i][1];
137 //        aFoundRow = found = row;
138 //        break;
139 //      }
140 //    }
141 //    if (! found) {
142 //      var row = table.insertRow(table.rows.length);
143 //      var warning_cell = document.createElement('TD');
144 //      warning_cell.style.color = '#ff0000';
145 //      warning_cell.colSpan = 2;
146 //      warning_cell.innerHTML = 'Calculated Tax - ' + itemdesc + ' - ' +
147 //                               taxlines[i][1] + ' will not be applied';
148 //      row.appendChild(warning_cell);
149 //    }
150 //  }
151 //
152 //  if (aFoundRow) {
153 //    sub_changed(table.rows[aFoundRow].getElementsByTagName('input').item(0));
154 //  }
155
156   var subtotal = parseFloat( argsHash['subtotal'] );
157
158   var taxtotal = parseFloat( argsHash['taxtotal'] );
159   document.getElementById('taxtotal_td').innerHTML =
160     '<% $money_char %>' + taxtotal.toFixed(2);
161
162   var total = subtotal + taxtotal;
163   document.getElementById('total_td').innerHTML =
164     '<% $money_char %>' + total.toFixed(2);
165   document.getElementById('total_el').value = total.toFixed(2);
166
167   //XXX reconcile both this and the reason selector wanteding to enable this
168   if ( total > 0 ) {
169     document.getElementById('credit_button').disabled = false;
170   }
171     
172 }
173
174 function calc_total(what) {
175
176   document.getElementById('credit_button').disabled = true;
177
178   var subtotal = 0;
179   // bah, a pain, just using an attribute var re = /^billpkgnum(\d+)$/;
180
181   var el = what.form.elements;
182   var billpkgnums = [];
183   var setuprecurs = [];
184   var amounts = [];
185   for (var i=0; i<el.length; i++) {
186     if ( el[i].type == 'checkbox' && el[i].checked ) {
187       subtotal += parseFloat( el[i].getAttribute('data-amount') );
188       amounts.push(     el[i].getAttribute('data-amount') );
189       billpkgnums.push( el[i].getAttribute('data-billpkgnum') );
190       setuprecurs.push( el[i].getAttribute('data-setuprecur') );
191     }
192   }
193
194   document.getElementById('subtotal_td').innerHTML =
195     '<% $money_char %>' + subtotal.toFixed(2);
196
197   var args = new Array(
198     'custnum',     '<% $custnum %>',
199     'subtotal',    subtotal,
200     'billpkgnums', billpkgnums.join(),
201     'setuprecurs', setuprecurs.join(),
202     'amounts',     amounts.join()
203   );
204
205   calculate_taxes( args, show_taxes );
206
207 }
208 </SCRIPT>
209
210 <%init>
211
212 my $curuser = $FS::CurrentUser::CurrentUser;
213 die "access denied" unless $curuser->access_right('Post credit');
214
215 #a tiny bit of false laziness w/search/cust_bill_pkg.cgi, but we're pretty
216 # specialized and a piece of UI, not a report
217 #slightly more false laziness w/httemplate/edit/elements/ApplicationCommon.html
218 # show_taxes & calc_total here/do_calculate_tax there
219
220 my $conf = new FS::Conf;
221 my $money_char = $conf->config('money_char') || '$';
222 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
223
224 $cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum';
225 my $custnum = $1;
226
227 my $cust_main = qsearchs({
228   'table'     => 'cust_main',
229   'hashref'   => { 'custnum' => $custnum },
230   'extra_sql' => ' AND '. $curuser->agentnums_sql,
231 }) or die 'unknown customer';
232
233 my @cust_bill_pkg = qsearch({
234   'select'    => 'cust_bill_pkg.*',
235   'table'     => 'cust_bill_pkg',
236   'addl_from' => 'LEFT JOIN cust_bill USING (invnum)',
237   'extra_sql' => "WHERE custnum = $custnum AND pkgnum != 0",
238   'order_by'  => 'ORDER BY invnum ASC, billpkgnum ASC',
239 });
240
241 my @items = map { my %hash = $_->disintegrate;
242                   map [ $_, $hash{$_} ],
243                     keys(%hash);
244                 }
245               @cust_bill_pkg;
246
247 #omit line items which have been previously credited?  would be nice
248
249 </%init>