last login reporting (#2952)
[freeside.git] / httemplate / view / svc_acct.cgi
1 % if ( $custnum ) { 
2
3   <% include("/elements/header.html","View $svc account") %>
4   <% include( '/elements/small_custview.html', $custnum, '', 1,
5      "${p}view/cust_main.cgi") %>
6   <BR>
7
8 % } else { 
9
10   <SCRIPT>
11   function areyousure(href) {
12       if (confirm("Permanently delete this account?") == true)
13           window.location.href = href;
14   }
15   </SCRIPT>
16   
17   <% include("/elements/header.html",'Account View', menubar(
18     "Cancel this (unaudited) account" =>
19             "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')",
20   )) %>
21
22 % } 
23
24 % if ( $part_svc->part_export_usage ) {
25 %
26 %  my $last_bill;
27 %  my %plandata;
28 %  if ( $cust_pkg ) {
29 %    #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really
30 %    #belong in plan data
31 %    %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
32 %                    split("\n", $cust_pkg->part_pkg->plandata );
33 %
34 %    $last_bill = $cust_pkg->last_bill;
35 %  } else {
36 %    $last_bill = 0;
37 %    %plandata = ();
38 %  }
39 %
40 %  my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time );
41 %  my $hour = int($seconds/3600);
42 %  my $min = int( ($seconds%3600) / 60 );
43 %  my $sec = $seconds%60;
44 %
45 %  my $input = $svc_acct->attribute_since_sqlradacct(
46 %    $last_bill, time, 'AcctInputOctets'
47 %  ) / 1048576;
48 %  my $output = $svc_acct->attribute_since_sqlradacct(
49 %    $last_bill, time, 'AcctOutputOctets'
50 %  ) / 1048576;
51 %
52 %
53
54
55   RADIUS session information<BR>
56   <% ntable('#cccccc',2) %>
57   <TR><TD BGCOLOR="#ffffff">
58 % if ( $seconds ) { 
59
60     Online <B><% $hour %></B>h <B><% $min %></B>m <B><% $sec %></B>s
61 % } else { 
62
63     Has not logged on
64 % } 
65 % if ( $cust_pkg ) { 
66
67     since last bill (<% time2str('%a %b %o %Y', $last_bill) %>)
68 % if ( length($plandata{recur_included_hours}) ) { 
69
70     - <% $plandata{recur_included_hours} %> total hours in plan
71 % } 
72
73     <BR>
74 % } else { 
75
76     (no billing cycle available for unaudited account)<BR>
77 % } 
78
79
80   Upload: <B><% sprintf("%.3f", $input) %></B> megabytes<BR>
81   Download: <B><% sprintf("%.3f", $output) %></B> megabytes<BR>
82   Last Login: <B><% $svc_acct->last_login_text %></B><BR>
83 % my $href = qq!<A HREF="${p}search/sqlradius.cgi?svcnum=$svcnum!; 
84
85   View session detail:
86       <% $href %>;begin=<% $last_bill %>">this billing cycle</A>
87     | <% $href %>;begin=<% time-15552000 %>">past six months</A>
88     | <% $href %>">all sessions</A>
89
90   </TD></TR></TABLE><BR>
91 % } 
92
93
94 <SCRIPT TYPE="text/javascript">
95 function enable_change () {
96   if ( document.OneTrueForm.svcpart.selectedIndex > 1 ) {
97     document.OneTrueForm.submit.disabled = false;
98   } else {
99     document.OneTrueForm.submit.disabled = true;
100   }
101 }
102 </SCRIPT>
103 <FORM NAME="OneTrueForm" ACTION="<%$p%>edit/process/cust_svc.cgi">
104 <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>">
105 <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
106 % #print qq!<BR><A HREF="../misc/sendconfig.cgi?$svcnum">Send account information</A>!; 
107
108 %  my @part_svc = ();
109 %  if ( $pkgnum ) { 
110 %    @part_svc = grep {    $_->svcdb   eq 'svc_acct'
111 %                       && $_->svcpart != $part_svc->svcpart }
112 %                $cust_pkg->available_part_svc;
113 %  } else {
114 %    @part_svc = qsearch('part_svc', {
115 %      svcdb    => 'svc_acct',
116 %      disabled => '',
117 %      svcpart  => { op=>'!=', value=>$part_svc->svcpart },
118 %    } );
119 %  }
120 %
121
122
123 Service #<B><% $svcnum %></B>
124 | <A HREF="<%$p%>edit/svc_acct.cgi?<%$svcnum%>">Edit this service</A>
125 % if ( @part_svc ) { 
126
127 | <SELECT NAME="svcpart" onChange="enable_change()">
128     <OPTION VALUE="">Change service</OPTION>
129     <OPTION VALUE="">--------------</OPTION>
130 % foreach my $opt_part_svc ( @part_svc ) { 
131
132       <OPTION VALUE="<% $opt_part_svc->svcpart %>"><% $opt_part_svc->svc %></OPTION>
133 % } 
134
135   </SELECT>
136   <INPUT NAME="submit" TYPE="submit" VALUE="Change" disabled>
137 % } 
138
139
140 <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
141
142 <TR>
143   <TD ALIGN="right">Service</TD>
144   <TD BGCOLOR="#ffffff"><% $part_svc->svc %></TD>
145 </TR>
146 <TR>
147   <TD ALIGN="right">Username</TD>
148   <TD BGCOLOR="#ffffff"><% $svc_acct->username %></TD>
149 </TR>
150 <TR>
151   <TD ALIGN="right">Domain</TD>
152   <TD BGCOLOR="#ffffff"><% $domain %></TD>
153 </TR>
154
155 <TR>
156   <TD ALIGN="right">Password</TD>
157   <TD BGCOLOR="#ffffff">
158 % my $password = $svc_acct->_password; 
159 % if ( $password =~ /^\*\w+\* (.*)$/ ) {
160 %         $password = $1;
161 %    
162
163       <I>(login disabled)</I>
164 % } 
165 % if ( $conf->exists('showpasswords') ) { 
166
167       <PRE><% encode_entities($password) %></PRE>
168 % } else { 
169
170       <I>(hidden)</I>
171 % } 
172
173
174   </TD>
175 </TR>
176 % $password = ''; 
177 % if ( $conf->exists('security_phrase') ) {
178 %     my $sec_phrase = $svc_acct->sec_phrase;
179 %
180
181   <TR>
182     <TD ALIGN="right">Security phrase</TD>
183     <TD BGCOLOR="#ffffff"><% $svc_acct->sec_phrase %></TD>
184   </TR>
185 % } 
186 % if ( $svc_acct->popnum ) {
187 %    my $svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum});
188 %
189
190   <TR>
191     <TD ALIGN="right">Access number</TD>
192     <TD BGCOLOR="#ffffff"><% $svc_acct_pop->text %></TD>
193   </TR>
194 % } 
195 % if ($svc_acct->uid ne '') { 
196
197   <TR>
198     <TD ALIGN="right">UID</TD>
199     <TD BGCOLOR="#ffffff"><% $svc_acct->uid %></TD>
200   </TR>
201 % } 
202 % if ($svc_acct->gid ne '') { 
203
204   <TR>
205     <TD ALIGN="right">GID</TD>
206     <TD BGCOLOR="#ffffff"><% $svc_acct->gid %></TD>
207   </TR>
208 % } 
209 % if ($svc_acct->finger ne '') { 
210
211   <TR>
212     <TD ALIGN="right">GECOS</TD>
213     <TD BGCOLOR="#ffffff"><% $svc_acct->finger %></TD>
214   </TR>
215 % } 
216 % if ($svc_acct->dir ne '') { 
217
218   <TR>
219     <TD ALIGN="right">Home directory</TD>
220     <TD BGCOLOR="#ffffff"><% $svc_acct->dir %></TD>
221   </TR>
222 % } 
223 % if ($svc_acct->shell ne '') { 
224
225   <TR>
226     <TD ALIGN="right">Shell</TD>
227     <TD BGCOLOR="#ffffff"><% $svc_acct->shell %></TD>
228   </TR>
229 % } 
230 % if ($svc_acct->quota ne '') { 
231
232   <TR>
233     <TD ALIGN="right">Quota</TD>
234     <TD BGCOLOR="#ffffff"><% $svc_acct->quota %></TD>
235   </TR>
236 % } 
237 % if ($svc_acct->slipip) { 
238
239   <TR>
240     <TD ALIGN="right">IP address</TD>
241     <TD BGCOLOR="#ffffff">
242       <% ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' )
243             ? "<I>(Dynamic)</I>"
244             : $svc_acct->slipip
245       %>
246     </TD>
247   </TR>
248 % } 
249 % my %ulabel = ( seconds    => 'Time',
250 %                upbytes    => 'Upload bytes',
251 %                downbytes  => 'Download bytes',
252 %                totalbytes => 'Total bytes',
253 %              );
254 % foreach my $uf ( keys %ulabel ) {
255 %   my $tf = $uf . "_threshold";
256 %   if ( $svc_acct->$uf ne '' ) {
257 %     my $v = $uf eq 'seconds'
258 %       ? (($svc_acct->$uf < 0 ? '-' : ''). duration_exact($svc_acct->$uf) )
259 %       : FS::UI::bytecount::display_bytecount($svc_acct->$uf);
260     <TR>
261       <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD>
262       <TD BGCOLOR="#ffffff"><% $v %></TD>
263     </TR>
264
265 %   }
266 % }
267 % foreach my $attribute ( grep /^radius_/, $svc_acct->fields ) {
268 %  $attribute =~ /^radius_(.*)$/;
269 %  my $pattribute = $FS::raddb::attrib{$1};
270 %
271
272   <TR>
273     <TD ALIGN="right">Radius (reply) <% $pattribute %></TD>
274     <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD>
275   </TR>
276 % } 
277 % foreach my $attribute ( grep /^rc_/, $svc_acct->fields ) {
278 %  $attribute =~ /^rc_(.*)$/;
279 %  my $pattribute = $FS::raddb::attrib{$1};
280 %
281
282   <TR>
283     <TD ALIGN="right">Radius (check) <% $pattribute %></TD>
284     <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD>
285   </TR>
286 % } 
287
288
289 <TR>
290   <TD ALIGN="right">RADIUS groups</TD>
291   <TD BGCOLOR="#ffffff"><% join('<BR>', $svc_acct->radius_groups) %></TD>
292 </TR>
293 %
294 %# Can this be abstracted further?  Maybe a library function like
295 %# widget('HTML', 'view', $svc_acct) ?  It would definitely make UI 
296 %# style management easier.
297 %
298 % foreach (sort { $a cmp $b } $svc_acct->virtual_fields) { 
299
300   <% $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)) %>
301 % } 
302
303
304 </TABLE></TD></TR></TABLE>
305 </FORM>
306 <BR><BR>
307
308 % if ( @svc_www ) {
309   Hosting
310   <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
311 %   foreach my $svc_www (@svc_www) {
312 %     my($label, $value) = $svc_www->cust_svc->label;
313 %     my $link = $p. 'view/svc_www.cgi?'. $svc_www->svcnum;
314       <TR>
315         <TD BGCOLOR="#ffffff">
316           <A HREF="<% $link %>"><% "$label: $value" %></A>
317         </TD>
318       </TR>
319 %   }
320   </TABLE></TD></TR></TABLE>
321   <BR><BR>
322 % }
323
324 <% join("<BR>", $conf->config('svc_acct-notes') ) %>
325 <BR><BR>
326
327 <% joblisting({'svcnum'=>$svcnum}, 1) %>
328
329 <% include('/elements/footer.html') %>
330 <%init>
331
332 die "access denied"
333   unless $FS::CurrentUser::CurrentUser->access_right('View customer services')
334       || $FS::CurrentUser::CurrentUser->access_right('View customer'); #XXX remove me
335
336 my $conf = new FS::Conf;
337
338 my $addl_from = ' LEFT JOIN cust_svc  USING ( svcnum  ) '.
339                 ' LEFT JOIN cust_pkg  USING ( pkgnum  ) '.
340                 ' LEFT JOIN cust_main USING ( custnum ) ';
341
342 my($query) = $cgi->keywords;
343 $query =~ /^(\d+)$/;
344 my $svcnum = $1;
345 my $svc_acct = qsearchs({
346   'select'    => 'svc_acct.*',
347   'table'     => 'svc_acct',
348   'addl_from' => $addl_from,
349   'hashref'   => { 'svcnum' => $svcnum },
350   'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
351 });
352 die "Unknown svcnum" unless $svc_acct;
353
354 #false laziness w/all svc_*.cgi
355 my $cust_svc = qsearchs( 'cust_svc' , { 'svcnum' => $svcnum } );
356 my $pkgnum = $cust_svc->getfield('pkgnum');
357 my($cust_pkg, $custnum);
358 if ($pkgnum) {
359   $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
360   $custnum = $cust_pkg->custnum;
361 } else {
362   $cust_pkg = '';
363   $custnum = '';
364 }
365 #eofalse
366
367 my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
368 die "Unknown svcpart" unless $part_svc;
369 my $svc = $part_svc->svc;
370
371 die 'Empty domsvc for svc_acct.svcnum '. $svc_acct->svcnum
372   unless $svc_acct->domsvc;
373 my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } );
374 die 'Unknown domain (domsvc '. $svc_acct->domsvc.
375     ' for svc_acct.svcnum '. $svc_acct->svcnum. ')'
376   unless $svc_domain;
377 my $domain = $svc_domain->domain;
378
379 my @svc_www = qsearch({
380   'select'    => 'svc_www.*',
381   'table'     => 'svc_www',
382   'addl_from' => $addl_from,
383   'hashref'   => { 'usersvc' => $svcnum },
384   #XXX shit outta luck if you somehow got them linked across agents
385   # maybe we should show but not link to them?  kinda makes sense...
386   # (maybe a specific ACL for this situation???)
387   'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql(
388                             'null_right' => 'View/link unlinked services'
389                           ),
390 });
391
392 </%init>