Merge branch 'master' of git.freeside.biz:/home/git/freeside
[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
480   my $payment_info = payment_info( 'session_id' => $session_id );
481
482   my $tr_amount_fee = mason_comp(
483     'session_id' => $session_id,
484     'comp'       => '/elements/tr-amount_fee.html',
485     'args'       => [ 'amount' => $payment_info->{'balance'},
486                     ],
487   );
488
489   $tr_amount_fee = $tr_amount_fee->{'error'} || $tr_amount_fee->{'output'};
490
491   $payment_info->{'tr_amount_fee'} = $tr_amount_fee;
492
493   $payment_info;
494 }
495
496 sub payment_results {
497
498   use Business::CreditCard 0.30;
499
500   #we should only do basic checking here for DoS attacks and things
501   #that couldn't be constructed by the web form...  let process_payment() do
502   #the rest, it gives better error messages
503
504   $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
505     or die "Illegal amount: ". $cgi->param('amount'); #!!!
506   my $amount = $1;
507
508   my $payinfo = $cgi->param('payinfo');
509   $payinfo =~ s/[^\dx]//g;
510   $payinfo =~ /^([\dx]{13,16}|[\dx]{8,9})$/
511     #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
512     or die "illegal card"; #!!!
513   $payinfo = $1;
514   unless ( $payinfo =~ /x/ ) {
515     validate($payinfo)
516       #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
517       or die "invalid card"; #!!!
518   }
519
520   if ( $cgi->param('card_type') ) {
521     cardtype($payinfo) eq $cgi->param('card_type')
522       #or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
523       or die "not a ". $cgi->param('card_type');
524   }
525
526   $cgi->param('paycvv') =~ /^\s*(.{0,4})\s*$/ or die "illegal CVV2";
527   my $paycvv = $1;
528
529   $cgi->param('month') =~ /^(\d{2})$/ or die "illegal month";
530   my $month = $1;
531   $cgi->param('year') =~ /^(\d{4})$/ or die "illegal year";
532   my $year = $1;
533
534   $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
535   my $payname = $1;
536
537   $cgi->param('address1') =~ /^(.{0,80})$/ or die "illegal address1";
538   my $address1 = $1;
539
540   $cgi->param('address2') =~ /^(.{0,80})$/ or die "illegal address2";
541   my $address2 = $1;
542
543   $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city";
544   my $city = $1;
545
546   $cgi->param('state') =~ /^(.{0,80})$/ or die "illegal state";
547   my $state = $1;
548
549   $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip";
550   my $zip = $1;
551
552   $cgi->param('country') =~ /^(.{0,2})$/ or die "illegal country";
553   my $country = $1;
554
555   my $save = 0;
556   $save = 1 if $cgi->param('save');
557
558   my $auto = 0;
559   $auto = 1 if $cgi->param('auto');
560
561   $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
562   my $paybatch = $1;
563
564   $cgi->param('discount_term') =~ /^(\d*)$/ or die "illegal discount_term";
565   my $discount_term = $1;
566
567
568   process_payment(
569     'session_id' => $session_id,
570     'payby'      => 'CARD',
571     'amount'     => $amount,
572     'payinfo'    => $payinfo,
573     'paycvv'     => $paycvv,
574     'month'      => $month,
575     'year'       => $year,
576     'payname'    => $payname,
577     'address1'   => $address1,
578     'address2'   => $address2,
579     'city'       => $city,
580     'state'      => $state,
581     'zip'        => $zip,
582     'country'    => $country,
583     'save'       => $save,
584     'auto'       => $auto,
585     'paybatch'   => $paybatch,
586     'discount_term' => $discount_term,
587   );
588
589 }
590
591 sub make_ach_payment {
592   payment_info( 'session_id' => $session_id );
593 }
594
595 sub ach_payment_results {
596
597   #we should only do basic checking here for DoS attacks and things
598   #that couldn't be constructed by the web form...  let process_payment() do
599   #the rest, it gives better error messages
600
601   $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
602     or die "illegal amount"; #!!!
603   my $amount = $1;
604
605   my $payinfo1 = $cgi->param('payinfo1');
606   $payinfo1 =~ s/[^\dx]//g;
607   $payinfo1 =~ /^([\dx]+)$/
608     or die "illegal account"; #!!!
609   $payinfo1 = $1;
610
611   my $payinfo2 = $cgi->param('payinfo2');
612   $payinfo2 =~ s/[^\dx]//g;
613   $payinfo2 =~ /^([\dx]+)$/
614     or die "illegal ABA/routing code"; #!!!
615   $payinfo2 = $1;
616
617   $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
618   my $payname = $1;
619
620   $cgi->param('paystate') =~ /^(.{0,2})$/ or die "illegal paystate";
621   my $paystate = $1;
622
623   $cgi->param('paytype') =~ /^(.{0,80})$/ or die "illegal paytype";
624   my $paytype = $1;
625
626   $cgi->param('ss') =~ /^(.{0,80})$/ or die "illegal ss";
627   my $ss = $1;
628
629   $cgi->param('stateid') =~ /^(.{0,80})$/ or die "illegal stateid";
630   my $stateid = $1;
631
632   $cgi->param('stateid_state') =~ /^(.{0,2})$/ or die "illegal stateid_state";
633   my $stateid_state = $1;
634
635   my $save = 0;
636   $save = 1 if $cgi->param('save');
637
638   my $auto = 0;
639   $auto = 1 if $cgi->param('auto');
640
641   $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
642   my $paybatch = $1;
643
644   process_payment(
645     'session_id' => $session_id,
646     'payby'      => 'CHEK',
647     'amount'     => $amount,
648     'payinfo1'   => $payinfo1,
649     'payinfo2'   => $payinfo2,
650     'month'      => '12',
651     'year'       => '2037',
652     'payname'    => $payname,
653     'paytype'    => $paytype,
654     'paystate'   => $paystate,
655     'ss'         => $ss,
656     'stateid'    => $stateid,
657     'stateid_state' => $stateid_state,
658     'save'       => $save,
659     'auto'       => $auto,
660     'paybatch'   => $paybatch,
661   );
662
663 }
664
665 sub make_thirdparty_payment {
666   payment_info('session_id' => $session_id);
667 }
668
669 sub post_thirdparty_payment {
670   $cgi->param('payby_method') =~ /^(CC|ECHECK)$/
671     or die "illegal payby method";
672   my $method = $1;
673   $cgi->param('amount') =~ /^(\d+(\.\d*)?)$/
674     or die "illegal amount";
675   my $amount = $1;
676   my $result = realtime_collect( 
677     'session_id' => $session_id,
678     'method' => $method, 
679     'amount' => $amount,
680   );
681   $result;
682 }
683
684 sub make_term_payment {
685   $cgi->param('amount') =~ /^(\d+\.\d{2})$/
686     or die "illegal payment amount";
687   my $balance = $1;
688   $cgi->param('discount_term') =~ /^(\d+)$/
689     or die "illegal discount term";
690   my $discount_term = $1;
691   $action = 'make_payment';
692   ({ %{payment_info( 'session_id' => $session_id )},
693     'balance' => $balance,
694     'discount_term' => $discount_term,
695   })
696 }
697
698 sub recharge_prepay {
699   customer_info( 'session_id' => $session_id );
700 }
701
702 sub recharge_results {
703
704   my $prepaid_cardnum = $cgi->param('prepaid_cardnum');
705   $prepaid_cardnum =~ s/\W//g;
706   $prepaid_cardnum =~ /^(\w*)$/ or die "illegal prepaid card number";
707   $prepaid_cardnum = $1;
708
709   process_prepay ( 'session_id'     => $session_id,
710                    'prepaid_cardnum' => $prepaid_cardnum,
711                  );
712 }
713
714 sub logout {
715   FS::SelfService::logout( 'session_id' => $session_id );
716 }
717
718 sub didreport {
719   my $result = did_report( 'session_id' => $session_id, 
720             'format' => $cgi->param('type'),
721             'recentonly' => $cgi->param('recentonly'),
722         );
723   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
724   $result;
725 }
726
727 sub provision {
728   my $result = list_pkgs( 'session_id' => $session_id );
729   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
730   $result->{'pkgpart'} = $cgi->param('pkgpart') if $cgi->param('pkgpart');
731   $result->{'filter'} = $cgi->param('filter') if $cgi->param('filter');
732   $result;
733 }
734
735 sub provision_svc {
736
737   my $result = part_svc_info(
738     'session_id' => $session_id,
739     map { $_ => $cgi->param($_) } qw( pkgnum svcpart svcnum ),
740   );
741   die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
742
743   $result->{'svcdb'} =~ /^svc_(.*)$/
744     #or return { 'error' => 'Unknown svcdb '. $result->{'svcdb'} };
745     or die 'Unknown svcdb '. $result->{'svcdb'};
746   $action .= "_$1";
747
748   $result->{'numavail'} = $cgi->param('numavail');
749   $result->{'lnp'} = $cgi->param('lnp');
750
751   $result;
752 }
753
754 sub process_svc_phone {
755     my @bulkdid = $cgi->param('bulkdid');
756     my $phonenum = $cgi->param('phonenum');
757     my $lnp = $cgi->param('lnp');
758
759     my $result;
760     if($lnp) {
761         $result = provision_phone (
762             'session_id' => $session_id,
763             'countrycode' => '1',
764              map { $_ => $cgi->param($_) } qw( pkgnum svcpart phonenum 
765                 lnp_desired_due_date lnp_other_provider 
766                 lnp_other_provider_account )
767         );
768     } else {
769         $result = provision_phone (
770             'session_id' => $session_id,
771             'bulkdid' => [ @bulkdid ],
772             'countrycode' => '1',
773              map { $_ => $cgi->param($_) } qw( pkgnum svcpart phonenum svcnum email forwarddst )
774         );
775     }
776
777     if ( exists $result->{'error'} && $result->{'error'} ) { 
778         $action = 'provision_svc_phone';
779         return {
780           $cgi->Vars,
781           %{ part_svc_info( 'session_id' => $session_id,
782                         map { $_ => $cgi->param($_) } qw( pkgnum svcpart svcnum )
783               )
784           },
785           'error' => $result->{'error'},
786         };
787   }
788
789   $result;
790 }
791
792 sub process_svc_acct {
793
794   my $result = provision_acct (
795     'session_id' => $session_id,
796     map { $_ => $cgi->param($_) } qw(
797       pkgnum svcpart username domsvc _password _password2 sec_phrase popnum )
798   );
799
800   if ( exists $result->{'error'} && $result->{'error'} ) { 
801     #warn "$result $result->{'error'}"; 
802     $action = 'provision_svc_acct';
803     return {
804       $cgi->Vars,
805       %{ part_svc_info( 'session_id' => $session_id,
806                         map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
807                       )
808       },
809       'error' => $result->{'error'},
810     };
811   } else {
812     #warn "$result $result->{'error'}"; 
813     return $result;
814   }
815
816 }
817
818 sub process_svc_external {
819   provision_external (
820     'session_id' => $session_id,
821     map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
822   );
823 }
824
825 sub delete_svc {
826   unprovision_svc(
827     'session_id' => $session_id,
828     'svcnum'     => $cgi->param('svcnum'),
829   );
830 }
831
832 sub view_usage {
833   list_svcs(
834     'session_id'  => $session_id,
835     'svcdb'       => [ 'svc_acct', 'svc_phone', 'svc_port', ],
836     'ncancelled'  => 1,
837   );
838 }
839
840 sub real_port_graph {
841     my $svcnum = $cgi->param('svcnum');
842     my $res = port_graph(
843             'session_id'  => $session_id,
844             'svcnum'      => $svcnum,
845             'beginning'   => str2time($cgi->param('start')." 00:00:00"),
846             'ending'    => str2time($cgi->param('end')." 23:59:59"),
847             );
848     my @usage = @{$res->{'usage'}};
849     my $png = $usage[0]->{'png'};
850     { 'content' => $png, 'format' => 'png' };
851 }
852
853 sub view_port_graph {
854     my $svcnum = $cgi->param('svcnum');
855     { 'svcnum' => $svcnum,
856       'start' => $cgi->param($svcnum.'_start'),
857       'end' => $cgi->param($svcnum.'_end'),
858     }
859 }
860
861 sub view_usage_details {
862       list_svc_usage(
863         'session_id'  => $session_id,
864         'svcnum'      => $cgi->param('svcnum'),
865         'beginning'   => $cgi->param('beginning') || '',
866         'ending'      => $cgi->param('ending') || '',
867       );
868 }
869
870 sub view_cdr_details {
871   list_cdr_usage(
872     'session_id'  => $session_id,
873     'svcnum'      => $cgi->param('svcnum'),
874     'beginning'   => $cgi->param('beginning') || '',
875     'ending'      => $cgi->param('ending') || '',
876   );
877 }
878
879 sub view_support_details {
880   list_support_usage(
881     'session_id'  => $session_id,
882     'svcnum'      => $cgi->param('svcnum'),
883     'beginning'   => $cgi->param('beginning') || '',
884     'ending'      => $cgi->param('ending') || '',
885   );
886 }
887
888 sub change_password {
889   list_svcs(
890     'session_id' => $session_id,
891     'svcdb'      => 'svc_acct',
892   );
893 };
894
895 sub process_change_password {
896
897   my $result = myaccount_passwd(
898     'session_id'    => $session_id,
899     map { $_ => $cgi->param($_) } qw( svcnum new_password new_password2 )
900   );
901
902   if ( exists $result->{'error'} && $result->{'error'} ) { 
903
904     $action = 'change_password';
905     return {
906       $cgi->Vars,
907       %{ list_svcs( 'session_id' => $session_id,
908                     'svcdb'      => 'svc_acct',
909                   )
910        },
911       #'svcnum' => $cgi->param('svcnum'),
912       'error'  => $result->{'error'}
913     };
914
915  } else {
916
917    return $result;
918
919  }
920
921 }
922
923 #--
924
925 sub do_template {
926   my $name = shift;
927   my $fill_in = shift;
928
929   $cgi->delete_all();
930   $fill_in->{'selfurl'} = $cgi->self_url;
931   $fill_in->{'cgi'} = \$cgi;
932
933   my $access_info = $session_id
934                       ? access_info( 'session_id' => $session_id )
935                       : {};
936   $fill_in->{$_} = $access_info->{$_} foreach keys %$access_info;
937
938   
939     if($result && ref($result) && $result->{'format'} && $result->{'content'}
940         && $result->{'format'} eq 'csv') {
941         print $cgi->header('-expires' => 'now',
942                 '-Content-Type' => 'text/csv',
943                 '-Content-Disposition' => "attachment;filename=output.csv",
944                 ),
945             $result->{'content'};
946     }
947     elsif($result && ref($result) && $result->{'format'} && $result->{'content'}
948          && $result->{'format'} eq 'xls') {
949         print $cgi->header('-expires' => 'now',
950                     '-Content-Type' => 'application/vnd.ms-excel',
951                     '-Content-Disposition' => "attachment;filename=output.xls",
952                     '-Content-Length' => length($result->{'content'}),
953                     ),
954                     $result->{'content'};
955     }
956     elsif($result && ref($result) && $result->{'format'} && $result->{'content'}
957          && $result->{'format'} eq 'png') {
958         print $cgi->header('-expires' => 'now',
959                     '-Content-Type' => 'image/png',
960                     ),
961                     $result->{'content'};
962     }
963     else {
964         my $source = "$template_dir/$name.html";
965         my $template = new Text::Template( TYPE       => 'FILE',
966                                          SOURCE     => $source,
967                                          DELIMITERS => [ '<%=', '%>' ],
968                                          UNTAINT    => 1,
969                                        )
970         or die $Text::Template::ERROR;
971
972         my $data = $template->fill_in( 
973             PACKAGE => 'FS::SelfService::_selfservicecgi',
974             HASH    => $fill_in,
975           ) || "Error processing template $source"; # at least print _something_
976           print $cgi->header( '-expires' => 'now' );
977           print $data;
978     }
979  }
980
981 #*FS::SelfService::_selfservicecgi::include = \&Text::Template::fill_in_file;
982
983 package FS::SelfService::_selfservicecgi;
984
985 use HTML::Entities;
986 use FS::SelfService qw(
987     regionselector popselector domainselector location_form didselector
988 );
989
990 #false laziness w/agent.cgi
991 use vars qw(@INCLUDE_ARGS);
992 sub include {
993   my $name = shift;
994
995   @INCLUDE_ARGS = @_;
996
997   my $template = new Text::Template( TYPE   => 'FILE',
998                                      SOURCE => "$main::template_dir/$name.html",
999                                      DELIMITERS => [ '<%=', '%>' ],
1000                                      UNTAINT => 1,                   
1001                                    )
1002     or die $Text::Template::ERROR;
1003
1004   $template->fill_in( PACKAGE => 'FS::SelfService::_selfservicecgi',
1005                       #HASH    => $fill_in
1006                     );
1007
1008 }
1009
1010 1;