fe8d08209798764d3ec5ea7ea37060cf9172b382
[freeside.git] / fs_selfservice / FS-SelfService / cgi / selfservice.cgi
1 #!/usr/bin/perl -Tw
2
3 use strict;
4 use vars qw($DEBUG $cgi $session_id $form_max $template_dir);
5 use subs qw(do_template);
6 use CGI;
7 use CGI::Carp qw(fatalsToBrowser);
8 use Text::Template;
9 use HTML::Entities;
10 use Date::Format;
11 use Date::Parse 'str2time';
12 use Number::Format 1.50;
13 use FS::SelfService qw(
14   access_info login_info login customer_info edit_info invoice
15   payment_info process_payment realtime_collect process_prepay
16   list_pkgs order_pkg signup_info order_recharge
17   part_svc_info provision_acct provision_external provision_phone
18   unprovision_svc change_pkg suspend_pkg domainselector
19   list_svcs list_svc_usage list_cdr_usage list_support_usage
20   myaccount_passwd list_invoices create_ticket get_ticket did_report
21   adjust_ticket_priority
22   mason_comp port_graph
23 );
24
25 $template_dir = '.';
26
27 $DEBUG = 0;
28
29 $form_max = 255;
30
31 $cgi = new CGI;
32
33 unless ( defined $cgi->param('session') ) {
34   my $login_info = login_info( 'agentnum' => scalar($cgi->param('agentnum')) );
35
36   do_template('login', $login_info );
37   exit;
38 }
39
40 if ( $cgi->param('session') eq 'login' ) {
41
42   $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i
43     or die "illegal username";
44   my $username = $1;
45
46   $cgi->param('domain') =~ /^\s*([\w\-\.]{0,$form_max})\s*$/
47     or die "illegal domain";
48   my $domain = $1;
49
50   $cgi->param('password') =~ /^(.{0,$form_max})$/
51     or die "illegal password";
52   my $password = $1;
53
54   my $rv = login(
55     'username' => $username,
56     'domain'   => $domain,
57     'password' => $password,
58   );
59   if ( $rv->{error} ) {
60     my $login_info = login_info( 'agentnum' => $cgi->param('agentnum') );
61     do_template('login', {
62       'error'    => $rv->{error},
63       'username' => $username,
64       'domain'   => $domain,
65       %$login_info,
66     } );
67     exit;
68   } else {
69     $cgi->param('session' => $rv->{session_id} );
70     $cgi->param('action'  => 'myaccount' );
71   }
72 }
73
74 $session_id = $cgi->param('session');
75
76 #order|pw_list XXX ???
77 my @actions = ( qw(
78   myaccount
79   tktcreate
80   tktview
81   ticket_priority
82   didreport
83   invoices
84   view_invoice
85   make_payment
86   make_ach_payment
87   make_term_payment
88   make_thirdparty_payment
89   post_thirdparty_payment
90   payment_results
91   ach_payment_results
92   recharge_prepay
93   recharge_results
94   logout
95   change_bill
96   change_ship
97   change_pay
98   process_change_bill
99   process_change_ship
100   process_change_pay
101   customer_order_pkg
102   process_order_pkg
103   customer_change_pkg
104   process_change_pkg
105   process_order_recharge
106   provision
107   provision_svc
108   process_svc_acct
109   process_svc_phone
110   process_svc_external
111   delete_svc
112   view_usage
113   view_usage_details
114   view_cdr_details
115   view_support_details
116   view_port_graph
117   real_port_graph
118   change_password
119   process_change_password
120   customer_suspend_pkg
121   process_suspend_pkg
122 ));
123  
124 $cgi->param('action') =~ ( '^(' . join('|', @actions) . ')$' )
125   or die "unknown action ". $cgi->param('action');
126 my $action = $1;
127
128 warn "calling $action sub\n"
129   if $DEBUG;
130 $FS::SelfService::DEBUG = $DEBUG;
131 my $result = eval "&$action();";
132 die $@ if $@;
133
134 warn Dumper($result) if $DEBUG;
135
136 if ( $result->{error} && ( $result->{error} eq "Can't resume session"
137   || $result->{error} eq "Expired session") ) { #ick
138
139   my $login_info = login_info();
140   do_template('login', $login_info);
141   exit;
142 }
143
144 #warn $result->{'open_invoices'};
145 #warn scalar(@{$result->{'open_invoices'}});
146
147 warn "processing template $action\n"
148   if $DEBUG;
149 do_template($action, {
150   'session_id' => $session_id,
151   'action'     => $action, #so the menu knows what tab we're on...
152   #%{ payment_info( 'session_id' => $session_id ) },  # cust_paybys for the menu
153   %{$result}
154 });
155
156 #--
157
158 use Data::Dumper;
159 sub myaccount { 
160   customer_info( 'session_id' => $session_id ); 
161 }
162
163 sub change_bill { my $payment_info =
164                     payment_info( 'session_id' => $session_id );
165                   return $payment_info if ( $payment_info->{'error'} );
166                   my $customer_info =
167                     customer_info( 'session_id' => $session_id );
168                   return { 
169                     %$payment_info,
170                     %$customer_info,
171                   };
172                 }
173 sub change_ship { change_bill(@_); }
174 sub change_pay { change_bill(@_); }
175
176 sub _process_change_info { 
177   my ($erroraction, @fields) = @_;
178
179   my $results = '';
180
181   $results ||= edit_info (
182     'session_id' => $session_id,
183     map { ($_ => $cgi->param($_)) } grep { defined($cgi->param($_)) } @fields,
184   );
185
186
187   if ( $results->{'error'} ) {
188     no strict 'refs';
189     $action = $erroraction;
190     return {
191       $cgi->Vars,
192       %{&$action()},
193       'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
194     };
195   } else {
196     return $results;
197   }
198 }
199
200 sub process_change_bill {
201         _process_change_info( 'change_bill', 
202           qw( first last company address1 address2 city state
203               county zip country daytime night fax )
204         );
205 }
206
207 sub process_change_ship {
208         my @list = map { "ship_$_" }
209                      qw( first last company address1 address2 city state
210                          county zip country daytime night fax 
211                        );
212         if ($cgi->param('same') eq 'Y') {
213           foreach (@list) { $cgi->param($_, '') }
214         }
215
216         _process_change_info( 'change_ship', @list );
217 }
218
219 sub process_change_pay {
220         my $postal = $cgi->param( 'postal_invoicing' );
221         my $payby  = $cgi->param( 'payby' );
222         my @list =
223           qw( payby payinfo payinfo1 payinfo2 month year payname
224               address1 address2 city county state zip country auto paytype
225               paystate ss stateid stateid_state invoicing_list
226             );
227         push @list, 'postal_invoicing' if $postal;
228         unless (    $payby ne 'BILL'
229                  || $postal
230                  || $cgi->param( 'invoicing_list' )
231                )
232         {
233           $action = 'change_pay';
234           return {
235             %{&change_pay()},
236             $cgi->Vars,
237             'error' => '<FONT COLOR="#FF0000">Postal or email required.</FONT>',
238           };
239         }
240         _process_change_info( 'change_pay', @list );
241 }
242
243 sub view_invoice {
244
245   $cgi->param('invnum') =~ /^(\d+)$/ or die "illegal invnum";
246   my $invnum = $1;
247
248   invoice( 'session_id' => $session_id,
249            'invnum'     => $invnum,
250          );
251
252 }
253
254 sub invoices {
255   list_invoices( 'session_id' => $session_id, );
256 }
257
258 sub tktcreate {
259   my $customer_info = customer_info( 'session_id' => $session_id );
260   return $customer_info if ( $customer_info->{'error'} );
261
262   my $requestor = "";
263   if ( $customer_info->{'invoicing_list'} ) {
264     my @requestor = split( /\s*\,\s*/, $customer_info->{'invoicing_list'} );
265     $requestor = $requestor[0] if scalar(@requestor);
266   }
267
268   return { 'requestor' => $requestor }
269     unless ($cgi->param('subject') && $cgi->param('message') &&
270         length($cgi->param('subject')) && length($cgi->param('message')));
271     
272  create_ticket( 'session_id' => $session_id,
273                         'subject' => $cgi->param('subject'),
274                         'message' => $cgi->param('message'), 
275                         'requestor' => $requestor,
276             );
277 }
278
279 sub tktview {
280  get_ticket(    'session_id' => $session_id,
281                 'ticket_id' => ($cgi->param('ticket_id') || ''),
282                 'subject'   => ($cgi->param('subject') || ''),
283                 'reply'     => ($cgi->param('reply') || ''),
284             );
285 }
286
287 sub ticket_priority {
288   my %values;
289   foreach ( $cgi->param ) {
290     if ( /^ticket(\d+)$/ ) {
291       # a 'ticket1001' param implies the existence of a 'priority1001' param
292       # but if that's empty, we need to send it as empty rather than forget
293       # it.
294       $values{$1} = $cgi->param("priority$1") || '';
295     }
296   }
297   $action = 'myaccount';
298   # this returns an updated customer_info for myaccount
299   adjust_ticket_priority( 'session_id' => $session_id,
300                           'values'     => \%values );
301 }
302
303 sub customer_order_pkg {
304   my $init_data = signup_info( 'customer_session_id' => $session_id );
305   return $init_data if ( $init_data->{'error'} );
306
307   my $customer_info = customer_info( 'session_id' => $session_id );
308   return $customer_info if ( $customer_info->{'error'} );
309
310   my $pkgselect = mason_comp(
311     'session_id' => $session_id,
312     'comp'       => '/edit/cust_main/first_pkg/select-part_pkg.html',
313     'args'       => [ 'password_verify' => 1,
314                       'onchange'        => 'enable_order_pkg()',
315                       'relurls'         => 1,
316                       'empty_label'     => 'Select package',
317                     ],
318   );
319
320   $pkgselect = $pkgselect->{'error'} || $pkgselect->{'output'};
321
322   return {
323     ( map { $_ => $init_data->{$_} }
324           qw( part_pkg security_phrase svc_acct_pop ),
325     ),
326     %$customer_info,
327     'pkg_selector' => $pkgselect,
328   };
329 }
330
331 sub customer_change_pkg {
332   my $init_data = signup_info( 'customer_session_id' => $session_id );
333   return $init_data if ( $init_data->{'error'} );
334
335   my $customer_info = customer_info( 'session_id' => $session_id );
336   return $customer_info if ( $customer_info->{'error'} );
337
338   return {
339     ( map { $_ => $init_data->{$_} }
340           qw( part_pkg security_phrase svc_acct_pop ),
341     ),
342     ( map { $_ => $cgi->param($_) }
343         qw( pkgnum pkg )
344     ),
345     %$customer_info,
346   };
347 }
348
349 sub process_order_pkg {
350
351   my $results = '';
352
353   my @params = (qw( custnum pkgpart ));
354   my $svcdb = '';
355   if ( $cgi->param('pkgpart_svcpart') =~ /^(\d+)_(\d+)$/ ) {
356     $cgi->param('pkgpart', $1);
357     $cgi->param('svcpart', $2);
358     push @params, 'svcpart';
359     $svcdb = $cgi->param('svcdb');
360     push @params, 'domsvc' if $svcdb eq 'svc_acct';
361   } else {
362     $svcdb = 'svc_acct';
363   }
364
365   if ( $svcdb eq 'svc_acct' ) {
366
367     push @params, qw( username _password _password2 sec_phrase popnum );
368
369     unless ( length($cgi->param('_password')) ) {
370       my $init_data = signup_info( 'customer_session_id' => $session_id );
371       $results = { 'error' => $init_data->{msgcat}{empty_password} };
372       $results = { 'error' => $init_data->{error} } if($init_data->{error});
373     }
374     if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
375       my $init_data = signup_info( 'customer_session_id' => $session_id );
376       $results = { 'error' => $init_data->{msgcat}{passwords_dont_match} };
377       $results = { 'error' => $init_data->{error} } if($init_data->{error});
378       $cgi->param('_password', '');
379       $cgi->param('_password2', '');
380     }
381
382   } elsif ( $svcdb eq 'svc_phone' ) {
383
384     push @params, qw( phonenum sip_password pin phone_name );
385
386   } else {
387     die "$svcdb not handled on process_order_pkg yet";
388   }
389
390   $results ||= order_pkg (
391     'session_id' => $session_id,
392     map { $_ => $cgi->param($_) } @params
393   );
394
395
396   if ( $results->{'error'} ) {
397     $action = 'customer_order_pkg';
398     return {
399       $cgi->Vars,
400       %{customer_order_pkg()},
401       'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
402     };
403   } else {
404     return $results;
405   }
406
407 }
408
409 sub process_change_pkg {
410
411   my $results = '';
412
413   $results ||= change_pkg (
414     'session_id' => $session_id,
415     map { $_ => $cgi->param($_) }
416         qw( pkgpart pkgnum )
417   );
418
419
420   if ( $results->{'error'} ) {
421     $action = 'customer_change_pkg';
422     return {
423       $cgi->Vars,
424       %{customer_change_pkg()},
425       'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
426     };
427   } else {
428     return $results;
429   }
430
431 }
432
433 sub process_suspend_pkg {
434   my $results = '';
435   $results = suspend_pkg (
436     'session_id' => $session_id,
437     map { $_ => $cgi->param($_) } 
438       qw( pkgnum )
439     );
440   if ( $results->{'error'} ) {
441     $action = 'provision';
442     return {
443       'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
444     }
445   }
446   else {
447     return $results;
448   }
449 }
450
451 sub process_order_recharge {
452
453   my $results = '';
454
455   $results ||= order_recharge (
456     'session_id' => $session_id,
457     map { $_ => $cgi->param($_) }
458         qw( svcnum )
459   );
460
461
462   if ( $results->{'error'} ) {
463     $action = 'view_usage';
464     if ($results->{'error'} eq '_decline') {
465       $results->{'error'} = "There has been an error processing your account.  Please contact customer support."
466     }
467     return {
468       $cgi->Vars,
469       %{view_usage()},
470       'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
471     };
472   } else {
473     return $results;
474   }
475
476 }
477
478 sub make_payment {
479   payment_info( 'session_id' => $session_id );
480 }
481
482 sub payment_results {
483
484   use Business::CreditCard 0.30;
485
486   #we should only do basic checking here for DoS attacks and things
487   #that couldn't be constructed by the web form...  let process_payment() do
488   #the rest, it gives better error messages
489
490   $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
491     or die "Illegal amount: ". $cgi->param('amount'); #!!!
492   my $amount = $1;
493
494   my $payinfo = $cgi->param('payinfo');
495   $payinfo =~ s/[^\dx]//g;
496   $payinfo =~ /^([\dx]{13,16}|[\dx]{8,9})$/
497     #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
498     or die "illegal card"; #!!!
499   $payinfo = $1;
500   unless ( $payinfo =~ /x/ ) {
501     validate($payinfo)
502       #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
503       or die "invalid card"; #!!!
504   }
505
506   if ( $cgi->param('card_type') ) {
507     cardtype($payinfo) eq $cgi->param('card_type')
508       #or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
509       or die "not a ". $cgi->param('card_type');
510   }
511
512   $cgi->param('paycvv') =~ /^\s*(.{0,4})\s*$/ or die "illegal CVV2";
513   my $paycvv = $1;
514
515   $cgi->param('month') =~ /^(\d{2})$/ or die "illegal month";
516   my $month = $1;
517   $cgi->param('year') =~ /^(\d{4})$/ or die "illegal year";
518   my $year = $1;
519
520   $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
521   my $payname = $1;
522
523   $cgi->param('address1') =~ /^(.{0,80})$/ or die "illegal address1";
524   my $address1 = $1;
525
526   $cgi->param('address2') =~ /^(.{0,80})$/ or die "illegal address2";
527   my $address2 = $1;
528
529   $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city";
530   my $city = $1;
531
532   $cgi->param('state') =~ /^(.{0,80})$/ or die "illegal state";
533   my $state = $1;
534
535   $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip";
536   my $zip = $1;
537
538   $cgi->param('country') =~ /^(.{0,2})$/ or die "illegal country";
539   my $country = $1;
540
541   my $save = 0;
542   $save = 1 if $cgi->param('save');
543
544   my $auto = 0;
545   $auto = 1 if $cgi->param('auto');
546
547   $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
548   my $paybatch = $1;
549
550   $cgi->param('discount_term') =~ /^(\d*)$/ or die "illegal discount_term";
551   my $discount_term = $1;
552
553
554   process_payment(
555     'session_id' => $session_id,
556     'payby'      => 'CARD',
557     'amount'     => $amount,
558     'payinfo'    => $payinfo,
559     'paycvv'     => $paycvv,
560     'month'      => $month,
561     'year'       => $year,
562     'payname'    => $payname,
563     'address1'   => $address1,
564     'address2'   => $address2,
565     'city'       => $city,
566     'state'      => $state,
567     'zip'        => $zip,
568     'country'    => $country,
569     'save'       => $save,
570     'auto'       => $auto,
571     'paybatch'   => $paybatch,
572     'discount_term' => $discount_term,
573   );
574
575 }
576
577 sub make_ach_payment {
578   payment_info( 'session_id' => $session_id );
579 }
580
581 sub ach_payment_results {
582
583   #we should only do basic checking here for DoS attacks and things
584   #that couldn't be constructed by the web form...  let process_payment() do
585   #the rest, it gives better error messages
586
587   $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
588     or die "illegal amount"; #!!!
589   my $amount = $1;
590
591   my $payinfo1 = $cgi->param('payinfo1');
592   $payinfo1 =~ s/[^\dx]//g;
593   $payinfo1 =~ /^([\dx]+)$/
594     or die "illegal account"; #!!!
595   $payinfo1 = $1;
596
597   my $payinfo2 = $cgi->param('payinfo2');
598   $payinfo2 =~ s/[^\dx]//g;
599   $payinfo2 =~ /^([\dx]+)$/
600     or die "illegal ABA/routing code"; #!!!
601   $payinfo2 = $1;
602
603   $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
604   my $payname = $1;
605
606   $cgi->param('paystate') =~ /^(.{0,2})$/ or die "illegal paystate";
607   my $paystate = $1;
608
609   $cgi->param('paytype') =~ /^(.{0,80})$/ or die "illegal paytype";
610   my $paytype = $1;
611
612   $cgi->param('ss') =~ /^(.{0,80})$/ or die "illegal ss";
613   my $ss = $1;
614
615   $cgi->param('stateid') =~ /^(.{0,80})$/ or die "illegal stateid";
616   my $stateid = $1;
617
618   $cgi->param('stateid_state') =~ /^(.{0,2})$/ or die "illegal stateid_state";
619   my $stateid_state = $1;
620
621   my $save = 0;
622   $save = 1 if $cgi->param('save');
623
624   my $auto = 0;
625   $auto = 1 if $cgi->param('auto');
626
627   $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
628   my $paybatch = $1;
629
630   process_payment(
631     'session_id' => $session_id,
632     'payby'      => 'CHEK',
633     'amount'     => $amount,
634     'payinfo1'   => $payinfo1,
635     'payinfo2'   => $payinfo2,
636     'month'      => '12',
637     'year'       => '2037',
638     'payname'    => $payname,
639     'paytype'    => $paytype,
640     'paystate'   => $paystate,
641     'ss'         => $ss,
642     'stateid'    => $stateid,
643     'stateid_state' => $stateid_state,
644     'save'       => $save,
645     'auto'       => $auto,
646     'paybatch'   => $paybatch,
647   );
648
649 }
650
651 sub make_thirdparty_payment {
652   payment_info('session_id' => $session_id);
653 }
654
655 sub post_thirdparty_payment {
656   $cgi->param('payby_method') =~ /^(CC|ECHECK)$/
657     or die "illegal payby method";
658   my $method = $1;
659   $cgi->param('amount') =~ /^(\d+(\.\d*)?)$/
660     or die "illegal amount";
661   my $amount = $1;
662   my $result = realtime_collect( 
663     'session_id' => $session_id,
664     'method' => $method, 
665     'amount' => $amount,
666   );
667   $result;
668 }
669
670 sub make_term_payment {
671   $cgi->param('amount') =~ /^(\d+\.\d{2})$/
672     or die "illegal payment amount";
673   my $balance = $1;
674   $cgi->param('discount_term') =~ /^(\d+)$/
675     or die "illegal discount term";
676   my $discount_term = $1;
677   $action = 'make_payment';
678   ({ %{payment_info( 'session_id' => $session_id )},
679     'balance' => $balance,
680     'discount_term' => $discount_term,
681   })
682 }
683
684 sub recharge_prepay {
685   customer_info( 'session_id' => $session_id );
686 }
687
688 sub recharge_results {
689
690   my $prepaid_cardnum = $cgi->param('prepaid_cardnum');
691   $prepaid_cardnum =~ s/\W//g;
692   $prepaid_cardnum =~ /^(\w*)$/ or die "illegal prepaid card number";
693   $prepaid_cardnum = $1;
694
695   process_prepay ( 'session_id'     => $session_id,
696                    'prepaid_cardnum' => $prepaid_cardnum,
697                  );
698 }
699
700 sub logout {
701   FS::SelfService::logout( 'session_id' => $session_id );
702 }
703
704 sub didreport {
705   my $result = did_report( 'session_id' => $session_id, 
706             'format' => $cgi->param('type'),
707             'recentonly' => $cgi->param('recentonly'),
708         );
709   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
710   $result;
711 }
712
713 sub provision {
714   my $result = list_pkgs( 'session_id' => $session_id );
715   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
716   $result->{'pkgpart'} = $cgi->param('pkgpart') if $cgi->param('pkgpart');
717   $result->{'filter'} = $cgi->param('filter') if $cgi->param('filter');
718   $result;
719 }
720
721 sub provision_svc {
722
723   my $result = part_svc_info(
724     'session_id' => $session_id,
725     map { $_ => $cgi->param($_) } qw( pkgnum svcpart svcnum ),
726   );
727   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
728
729   $result->{'svcdb'} =~ /^svc_(.*)$/
730     #or return { 'error' => 'Unknown svcdb '. $result->{'svcdb'} };
731     or die 'Unknown svcdb '. $result->{'svcdb'};
732   $action .= "_$1";
733
734   $result->{'numavail'} = $cgi->param('numavail');
735   $result->{'lnp'} = $cgi->param('lnp');
736
737   $result;
738 }
739
740 sub process_svc_phone {
741     my @bulkdid = $cgi->param('bulkdid');
742     my $phonenum = $cgi->param('phonenum');
743     my $lnp = $cgi->param('lnp');
744
745     my $result;
746     if($lnp) {
747         $result = provision_phone (
748             'session_id' => $session_id,
749             'countrycode' => '1',
750              map { $_ => $cgi->param($_) } qw( pkgnum svcpart phonenum 
751                 lnp_desired_due_date lnp_other_provider 
752                 lnp_other_provider_account )
753         );
754     } else {
755         $result = provision_phone (
756             'session_id' => $session_id,
757             'bulkdid' => [ @bulkdid ],
758             'countrycode' => '1',
759              map { $_ => $cgi->param($_) } qw( pkgnum svcpart phonenum svcnum email forwarddst )
760         );
761     }
762
763     if ( exists $result->{'error'} && $result->{'error'} ) { 
764         $action = 'provision_svc_phone';
765         return {
766           $cgi->Vars,
767           %{ part_svc_info( 'session_id' => $session_id,
768                         map { $_ => $cgi->param($_) } qw( pkgnum svcpart svcnum )
769               )
770           },
771           'error' => $result->{'error'},
772         };
773   }
774
775   $result;
776 }
777
778 sub process_svc_acct {
779
780   my $result = provision_acct (
781     'session_id' => $session_id,
782     map { $_ => $cgi->param($_) } qw(
783       pkgnum svcpart username domsvc _password _password2 sec_phrase popnum )
784   );
785
786   if ( exists $result->{'error'} && $result->{'error'} ) { 
787     #warn "$result $result->{'error'}"; 
788     $action = 'provision_svc_acct';
789     return {
790       $cgi->Vars,
791       %{ part_svc_info( 'session_id' => $session_id,
792                         map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
793                       )
794       },
795       'error' => $result->{'error'},
796     };
797   } else {
798     #warn "$result $result->{'error'}"; 
799     return $result;
800   }
801
802 }
803
804 sub process_svc_external {
805   provision_external (
806     'session_id' => $session_id,
807     map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
808   );
809 }
810
811 sub delete_svc {
812   unprovision_svc(
813     'session_id' => $session_id,
814     'svcnum'     => $cgi->param('svcnum'),
815   );
816 }
817
818 sub view_usage {
819   list_svcs(
820     'session_id'  => $session_id,
821     'svcdb'       => [ 'svc_acct', 'svc_phone', 'svc_port', ],
822     'ncancelled'  => 1,
823   );
824 }
825
826 sub real_port_graph {
827     my $svcnum = $cgi->param('svcnum');
828     my $res = port_graph(
829             'session_id'  => $session_id,
830             'svcnum'      => $svcnum,
831             'beginning'   => str2time($cgi->param('start')." 00:00:00"),
832             'ending'    => str2time($cgi->param('end')." 23:59:59"),
833             );
834     my @usage = @{$res->{'usage'}};
835     my $png = $usage[0]->{'png'};
836     { 'content' => $png, 'format' => 'png' };
837 }
838
839 sub view_port_graph {
840     my $svcnum = $cgi->param('svcnum');
841     { 'svcnum' => $svcnum,
842       'start' => $cgi->param($svcnum.'_start'),
843       'end' => $cgi->param($svcnum.'_end'),
844     }
845 }
846
847 sub view_usage_details {
848       list_svc_usage(
849         'session_id'  => $session_id,
850         'svcnum'      => $cgi->param('svcnum'),
851         'beginning'   => $cgi->param('beginning') || '',
852         'ending'      => $cgi->param('ending') || '',
853       );
854 }
855
856 sub view_cdr_details {
857   list_cdr_usage(
858     'session_id'  => $session_id,
859     'svcnum'      => $cgi->param('svcnum'),
860     'beginning'   => $cgi->param('beginning') || '',
861     'ending'      => $cgi->param('ending') || '',
862   );
863 }
864
865 sub view_support_details {
866   list_support_usage(
867     'session_id'  => $session_id,
868     'svcnum'      => $cgi->param('svcnum'),
869     'beginning'   => $cgi->param('beginning') || '',
870     'ending'      => $cgi->param('ending') || '',
871   );
872 }
873
874 sub change_password {
875   list_svcs(
876     'session_id' => $session_id,
877     'svcdb'      => 'svc_acct',
878   );
879 };
880
881 sub process_change_password {
882
883   my $result = myaccount_passwd(
884     'session_id'    => $session_id,
885     map { $_ => $cgi->param($_) } qw( svcnum new_password new_password2 )
886   );
887
888   if ( exists $result->{'error'} && $result->{'error'} ) { 
889
890     $action = 'change_password';
891     return {
892       $cgi->Vars,
893       %{ list_svcs( 'session_id' => $session_id,
894                     'svcdb'      => 'svc_acct',
895                   )
896        },
897       #'svcnum' => $cgi->param('svcnum'),
898       'error'  => $result->{'error'}
899     };
900
901  } else {
902
903    return $result;
904
905  }
906
907 }
908
909 #--
910
911 sub do_template {
912   my $name = shift;
913   my $fill_in = shift;
914
915   $cgi->delete_all();
916   $fill_in->{'selfurl'} = $cgi->self_url;
917   $fill_in->{'cgi'} = \$cgi;
918
919   my $access_info = $session_id
920                       ? access_info( 'session_id' => $session_id )
921                       : {};
922   $fill_in->{$_} = $access_info->{$_} foreach keys %$access_info;
923
924   
925     if($result && ref($result) && $result->{'format'} && $result->{'content'}
926         && $result->{'format'} eq 'csv') {
927         print $cgi->header('-expires' => 'now',
928                 '-Content-Type' => 'text/csv',
929                 '-Content-Disposition' => "attachment;filename=output.csv",
930                 ),
931             $result->{'content'};
932     }
933     elsif($result && ref($result) && $result->{'format'} && $result->{'content'}
934          && $result->{'format'} eq 'xls') {
935         print $cgi->header('-expires' => 'now',
936                     '-Content-Type' => 'application/vnd.ms-excel',
937                     '-Content-Disposition' => "attachment;filename=output.xls",
938                     '-Content-Length' => length($result->{'content'}),
939                     ),
940                     $result->{'content'};
941     }
942     elsif($result && ref($result) && $result->{'format'} && $result->{'content'}
943          && $result->{'format'} eq 'png') {
944         print $cgi->header('-expires' => 'now',
945                     '-Content-Type' => 'image/png',
946                     ),
947                     $result->{'content'};
948     }
949     else {
950         my $source = "$template_dir/$name.html";
951         my $template = new Text::Template( TYPE       => 'FILE',
952                                          SOURCE     => $source,
953                                          DELIMITERS => [ '<%=', '%>' ],
954                                          UNTAINT    => 1,
955                                        )
956         or die $Text::Template::ERROR;
957
958         my $data = $template->fill_in( 
959             PACKAGE => 'FS::SelfService::_selfservicecgi',
960             HASH    => $fill_in,
961           ) || "Error processing template $source"; # at least print _something_
962           print $cgi->header( '-expires' => 'now' );
963           print $data;
964     }
965  }
966
967 #*FS::SelfService::_selfservicecgi::include = \&Text::Template::fill_in_file;
968
969 package FS::SelfService::_selfservicecgi;
970
971 use HTML::Entities;
972 use FS::SelfService qw(
973     regionselector popselector domainselector location_form didselector
974 );
975
976 #false laziness w/agent.cgi
977 use vars qw(@INCLUDE_ARGS);
978 sub include {
979   my $name = shift;
980
981   @INCLUDE_ARGS = @_;
982
983   my $template = new Text::Template( TYPE   => 'FILE',
984                                      SOURCE => "$main::template_dir/$name.html",
985                                      DELIMITERS => [ '<%=', '%>' ],
986                                      UNTAINT => 1,                   
987                                    )
988     or die $Text::Template::ERROR;
989
990   $template->fill_in( PACKAGE => 'FS::SelfService::_selfservicecgi',
991                       #HASH    => $fill_in
992                     );
993
994 }
995
996 1;