92fc6361d0ec71d41cffd4217dae818ad1aaf5ae
[freeside.git] / FS / FS / ClientAPI / Signup.pm
1 package FS::ClientAPI::Signup;
2
3 use strict;
4 use Tie::RefHash;
5 use FS::Conf;
6 use FS::Record qw(qsearch qsearchs dbdef);
7 use FS::agent;
8 use FS::cust_main_county;
9 use FS::part_pkg;
10 use FS::svc_acct_pop;
11 use FS::cust_main;
12 use FS::cust_pkg;
13 use FS::Msgcat qw(gettext);
14
15 use FS::ClientAPI; #hmm
16 FS::ClientAPI->register_handlers(
17   'Signup/signup_info'  => \&signup_info,
18   'Signup/new_customer' => \&new_customer,
19 );
20
21 sub signup_info {
22   #my $packet = shift;
23
24   my $conf = new FS::Conf;
25
26   use vars qw($signup_info); #cache for performance;
27   $signup_info ||= {
28
29     'cust_main_county' =>
30       [ map { $_->hashref } qsearch('cust_main_county', {}) ],
31
32     'agent' =>
33       [
34         map { $_->hashref }
35           qsearch('agent', dbdef->table('agent')->column('disabled')
36                              ? { 'disabled' => '' }
37                              : {}
38                  )
39       ],
40
41     'agentnum2part_pkg' =>
42       {
43         map {
44           my $href = $_->pkgpart_hashref;
45           $_->agentnum =>
46             [
47               map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
48                 grep { $_->svcpart('svc_acct') && $href->{ $_->pkgpart } }
49                   qsearch( 'part_pkg', { 'disabled' => '' } )
50             ];
51         } qsearch('agent', dbdef->table('agent')->column('disabled')
52                              ? { 'disabled' => '' }
53                              : {}
54                  )
55       },
56
57     'svc_acct_pop' => [ map { $_->hashref } qsearch('svc_acct_pop',{} ) ],
58
59     'security_phrase' => $conf->exists('security_phrase'),
60
61     'payby' => [ $conf->config('signup_server-payby') ],
62
63     'cvv_enabled' => defined dbdef->table('cust_main')->column('paycvv'),
64
65     'msgcat' => { map { $_=>gettext($_) } qw(
66       passwords_dont_match invalid_card unknown_card_type not_a
67     ) },
68
69     'statedefault' => $conf->config('statedefault') || 'CA',
70
71     'countrydefault' => $conf->config('countrydefault') || 'US',
72
73   };
74
75   if (
76     $conf->config('signup_server-default_agentnum')
77     && !exists $signup_info->{'part_pkg'} #cache for performance
78   ) {
79     my $agentnum = $conf->config('signup_server-default_agentnum');
80     my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } )
81       or die "fatal: signup_server-default_agentnum $agentnum not found\n";
82     my $pkgpart_href = $agent->pkgpart_hashref;
83
84     $signup_info->{'part_pkg'} = [
85       #map { $_->hashref }
86       map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
87         grep { $_->svcpart('svc_acct') && $pkgpart_href->{ $_->pkgpart } }
88           qsearch( 'part_pkg', { 'disabled' => '' } )
89     ];
90   }
91
92   $signup_info;
93
94 }
95
96 sub new_customer {
97   my $packet = shift;
98
99   my $conf = new FS::Conf;
100   
101   #things that aren't necessary in base class, but are for signup server
102     #return "Passwords don't match"
103     #  if $hashref->{'_password'} ne $hashref->{'_password2'}
104   return { 'error' => gettext('empty_password') }
105     unless $packet->{'_password'};
106   # a bit inefficient for large numbers of pops
107   return { 'error' => gettext('no_access_number_selected') }
108     unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} ));
109
110   #shares some stuff with htdocs/edit/process/cust_main.cgi... take any
111   # common that are still here and library them.
112   my $cust_main = new FS::cust_main ( {
113     #'custnum'          => '',
114     'agentnum'      => $packet->{agentnum}
115                        || $conf->config('signup_server-default_agentnum'),
116     'refnum'        => $packet->{refnum}
117                        || $conf->config('signup_server-default_refnum'),
118
119     map { $_ => $packet->{$_} } qw(
120       last first ss company address1 address2 city county state zip country
121       daytime night fax payby payinfo paycvv paydate payname referral_custnum
122       comments
123     ),
124
125   } );
126
127   return { 'error' => "Illegal payment type" }
128     unless grep { $_ eq $packet->{'payby'} }
129                 $conf->config('signup_server-payby');
130
131   $cust_main->payinfo($cust_main->daytime)
132     if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo;
133
134   my @invoicing_list = split( /\s*\,\s*/, $packet->{'invoicing_list'} );
135
136   $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/;
137   my $pkgpart = $1;
138   return { 'error' => 'Please select a package' } unless $pkgpart; #msgcat
139
140   my $part_pkg =
141     qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } )
142       or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" };
143   my $svcpart = $part_pkg->svcpart('svc_acct');
144
145   my $cust_pkg = new FS::cust_pkg ( {
146     #later#'custnum' => $custnum,
147     'pkgpart' => $packet->{'pkgpart'},
148   } );
149   my $error = $cust_pkg->check;
150   return { 'error' => $error } if $error;
151
152   my $svc_acct = new FS::svc_acct ( {
153     'svcpart'   => $svcpart,
154     map { $_ => $packet->{$_} }
155       qw( username _password sec_phrase popnum ),
156   } );
157
158   my $y = $svc_acct->setdefault; # arguably should be in new method
159   return { 'error' => $y } if $y && !ref($y);
160
161   $error = $svc_acct->check;
162   return { 'error' => $error } if $error;
163
164   use Tie::RefHash;
165   tie my %hash, 'Tie::RefHash';
166   %hash = ( $cust_pkg => [ $svc_acct ] );
167   #msgcat
168   $error = $cust_main->insert( \%hash, \@invoicing_list, 'noexport' => 1 );
169   return { 'error' => $error } if $error;
170
171   if ( $conf->exists('signup_server-realtime') ) {
172
173     #warn "[fs_signup_server] Billing customer...\n" if $Debug;
174
175     my $bill_error = $cust_main->bill;
176     #warn "[fs_signup_server] error billing new customer: $bill_error"
177     #  if $bill_error;
178
179     $cust_main->apply_payments;
180     $cust_main->apply_credits;
181
182     $bill_error = $cust_main->collect;
183     #warn "[fs_signup_server] error collecting from new customer: $bill_error"
184     #  if $bill_error;
185
186     if ( $cust_main->balance > 0 ) {
187
188       #this makes sense.  credit is "un-doing" the invoice
189       $cust_main->credit( $cust_main->balance, 'signup server decline' );
190       $cust_main->apply_credits;
191
192       #should check list for errors...
193       #$cust_main->suspend;
194       local $FS::svc_Common::noexport_hack = 1;
195       $cust_main->cancel('quiet'=>1);
196
197       return { 'error' => '_decline' };
198     }
199
200   }
201   $cust_main->reexport;
202
203   return { error => '' };
204
205 }
206
207 1;