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