1 package FS::ClientAPI::MyAccount;
5 use Digest::MD5 qw(md5_hex);
7 use Cache::SharedMemoryCache; #store in db?
8 use FS::CGI qw(small_custview); #doh
10 use FS::Record qw(qsearchs);
17 use FS::ClientAPI; #hmm
18 FS::ClientAPI->register_handlers(
19 'MyAccount/login' => \&login,
20 'MyAccount/customer_info' => \&customer_info,
21 'MyAccount/edit_info' => \&edit_info,
22 'MyAccount/invoice' => \&invoice,
23 'MyAccount/cancel' => \&cancel,
24 'MyAccount/list_pkgs' => \&list_pkgs,
25 'MyAccount/order_pkg' => \&order_pkg,
26 'MyAccount/cancel_pkg' => \&cancel_pkg,
27 'MyAccount/charge' => \&charge,
30 use vars qw( @cust_main_editable_fields );
31 @cust_main_editable_fields = qw(
32 first last company address1 address2 city
33 county state zip country daytime night fax
34 ship_first ship_last ship_company ship_address1 ship_address2 ship_city
35 ship_state ship_zip ship_country ship_daytime ship_night ship_fax
39 my $cache = new Cache::SharedMemoryCache( {
40 'namespace' => 'FS::ClientAPI::MyAccount',
43 #false laziness w/FS::ClientAPI::passwd::passwd
47 my $svc_domain = qsearchs('svc_domain', { 'domain' => $p->{'domain'} } )
48 or return { error => 'Domain '. $p->{'domain'}. ' not found' };
50 my $svc_acct = qsearchs( 'svc_acct', { 'username' => $p->{'username'},
51 'domsvc' => $svc_domain->svcnum, }
53 return { error => 'User not found.' } unless $svc_acct;
54 return { error => 'Incorrect password.' }
55 unless $svc_acct->check_password($p->{'password'});
58 'svcnum' => $svc_acct->svcnum,
61 my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
63 my $cust_main = $cust_pkg->cust_main;
64 $session->{'custnum'} = $cust_main->custnum;
69 $session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
70 } until ( ! defined $cache->get($session_id) ); #just in case
72 $cache->set( $session_id, $session, '1 hour' );
74 return { 'error' => '',
75 'session_id' => $session_id,
81 my $session = $cache->get($p->{'session_id'})
82 or return { 'error' => "Can't resume session" }; #better error message
86 my $custnum = $session->{'custnum'};
88 if ( $custnum ) { #customer record
90 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
91 or return { 'error' => "unknown custnum $custnum" };
93 $return{balance} = $cust_main->balance;
98 date => time2str("%b %o, %Y", $_->_date),
101 } $cust_main->open_cust_bill;
102 $return{open_invoices} = \@open;
104 my $conf = new FS::Conf;
105 $return{small_custview} =
106 small_custview( $cust_main, $conf->config('defaultcountry') );
108 $return{name} = $cust_main->first. ' '. $cust_main->get('last');
110 for (@cust_main_editable_fields) {
111 $return{$_} = $cust_main->get($_);
114 } else { #no customer record
116 my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $session->{'svcnum'} } )
117 or die "unknown svcnum";
118 $return{name} = $svc_acct->email;
123 return { 'error' => '',
124 'custnum' => $custnum,
132 my $session = $cache->get($p->{'session_id'})
133 or return { 'error' => "Can't resume session" }; #better error message
135 my $custnum = $session->{'custnum'}
136 or return { 'error' => "no customer record" };
138 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
139 or return { 'error' => "unknown custnum $custnum" };
141 my $new = new FS::cust_main { $cust_main->hash };
142 $new->set( $_ => $p->{$_} )
143 foreach grep { exists $p->{$_} } @cust_main_editable_fields;
144 my $error = $new->replace($cust_main);
145 return { 'error' => $error } if $error;
148 return { 'error' => '' };
153 my $session = $cache->get($p->{'session_id'})
154 or return { 'error' => "Can't resume session" }; #better error message
156 my $custnum = $session->{'custnum'};
158 my $invnum = $p->{'invnum'};
160 my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum,
161 'custnum' => $custnum } )
162 or return { 'error' => "Can't find invnum" };
166 return { 'error' => '',
168 'invoice_text' => join('', $cust_bill->print_text ),
175 my $session = $cache->get($p->{'session_id'})
176 or return { 'error' => "Can't resume session" }; #better error message
178 my $custnum = $session->{'custnum'};
180 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
181 or return { 'error' => "unknown custnum $custnum" };
183 my @errors = $cust_main->cancel( 'quiet'=>1 );
185 my $error = scalar(@errors) ? join(' / ', @errors) : '';
187 return { 'error' => $error };
193 my $session = $cache->get($p->{'session_id'})
194 or return { 'error' => "Can't resume session" }; #better error message
196 my $custnum = $session->{'custnum'};
198 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
199 or return { 'error' => "unknown custnum $custnum" };
201 return { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
207 my $session = $cache->get($p->{'session_id'})
208 or return { 'error' => "Can't resume session" }; #better error message
210 my $custnum = $session->{'custnum'};
212 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
213 or return { 'error' => "unknown custnum $custnum" };
215 #false laziness w/ClientAPI/Signup.pm
217 my $cust_pkg = new FS::cust_pkg ( {
218 'custnum' => $custnum,
219 'pkgpart' => $p->{'pkgpart'},
221 my $error = $cust_pkg->check;
222 return { 'error' => $error } if $error;
224 my $svc_acct = new FS::svc_acct ( {
225 'svcpart' => $p->{'svcpart'} || $cust_pkg->part_pkg->svcpart('svc_acct'),
226 map { $_ => $p->{$_} }
227 qw( username _password sec_phrase popnum ),
232 while ( length($p->{"snarf_machine$snarfnum"}) ) {
233 my $acct_snarf = new FS::acct_snarf ( {
234 'machine' => $p->{"snarf_machine$snarfnum"},
235 'protocol' => $p->{"snarf_protocol$snarfnum"},
236 'username' => $p->{"snarf_username$snarfnum"},
237 '_password' => $p->{"snarf_password$snarfnum"},
240 push @acct_snarf, $acct_snarf;
242 $svc_acct->child_objects( \@acct_snarf );
244 my $y = $svc_acct->setdefault; # arguably should be in new method
245 return { 'error' => $y } if $y && !ref($y);
247 $error = $svc_acct->check;
248 return { 'error' => $error } if $error;
251 tie my %hash, 'Tie::RefHash';
252 %hash = ( $cust_pkg => [ $svc_acct ] );
254 $error = $cust_main->order_pkgs( \%hash, '', 'noexport' => 1 );
255 return { 'error' => $error } if $error;
257 my $conf = new FS::Conf;
258 if ( $conf->exists('signup_server-realtime') ) {
260 my $old_balance = $cust_main->balance;
262 my $bill_error = $cust_main->bill;
263 $cust_main->apply_payments;
264 $cust_main->apply_credits;
265 $bill_error = $cust_main->collect;
267 if ( $cust_main->balance > $old_balance ) {
268 $cust_pkg->cancel('quiet'=>1);
269 return { 'error' => '_decline' };
278 return { error => '' };
284 my $session = $cache->get($p->{'session_id'})
285 or return { 'error' => "Can't resume session" }; #better error message
287 my $custnum = $session->{'custnum'};
289 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
290 or return { 'error' => "unknown custnum $custnum" };
292 my $pkgnum = $session->{'pkgnum'};
294 my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,
295 'pkgnum' => $pkgnum, } )
296 or return { 'error' => "unknown pkgnum $pkgnum" };
298 my $error = $cust_main->cancel( 'quiet'=>1 );
299 return { 'error' => $error };