big update for reseller interface
[freeside.git] / FS / FS / ClientAPI / Agent.pm
1 package FS::ClientAPI::Agent;
2
3 #some false laziness w/MyAccount
4
5 use strict;
6 use vars qw($cache);
7 use Digest::MD5 qw(md5_hex);
8 use Cache::SharedMemoryCache; #store in db?
9 use FS::Record qw(qsearchs qsearch dbdef dbh);
10 use FS::agent;
11 use FS::cust_main;
12
13 use FS::ClientAPI;
14 FS::ClientAPI->register_handlers(
15   'Agent/agent_login'          => \&agent_login,
16   'Agent/agent_logout'         => \&agent_logout,
17   'Agent/agent_info'           => \&agent_info,
18   'Agent/agent_list_customers' => \&agent_list_customers,
19 );
20
21 #store in db?
22 my $cache = new Cache::SharedMemoryCache( {
23    'namespace' => 'FS::ClientAPI::Agent',
24 } );
25
26 sub agent_login {
27   my $p = shift;
28
29   #don't allow a blank login to first unconfigured agent with no user/pass
30   return { error => 'Must specify your reseller username and password.' }
31     unless length($p->{'username'}) && length($p->{'password'});
32
33   my $agent = qsearchs( 'agent', {
34     'username'  => $p->{'username'},
35     '_password' => $p->{'password'},
36   } );
37
38   unless ( $agent ) { return { error => 'Incorrect password.' } }
39
40   my $session = { 
41     'agentnum' => $agent->agentnum,
42     'agent'    => $agent->agent,
43   };
44
45   my $session_id;
46   do {
47     $session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
48   } until ( ! defined $cache->get($session_id) ); #just in case
49
50   $cache->set( $session_id, $session, '1 hour' );
51
52   { 'error'      => '',
53     'session_id' => $session_id,
54   };
55 }
56
57 sub agent_logout {
58   my $p = shift;
59   if ( $p->{'session_id'} ) {
60     $cache->remove($p->{'session_id'});
61     return { 'error' => '' };
62   } else {
63     return { 'error' => "Can't resume session" }; #better error message
64   }
65 }
66
67 sub agent_info {
68   my $p = shift;
69
70   my $session = $cache->get($p->{'session_id'})
71     or return { 'error' => "Can't resume session" }; #better error message
72
73   #my %return;
74
75   my $agentnum = $session->{'agentnum'};
76
77   my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } )
78     or return { 'error' => "unknown agentnum $agentnum" };
79
80   { 'error'        => '',
81     'agentnum'     => $agentnum,
82     'agent'        => $agent->agent,
83     'num_prospect' => $agent->num_prospect_cust_main,
84     'num_active'   => $agent->num_active_cust_main,
85     'num_susp'     => $agent->num_susp_cust_main,
86     'num_cancel'   => $agent->num_cancel_cust_main,
87     #%return,
88   };
89
90 }
91
92 sub agent_list_customers {
93   my $p = shift;
94
95   my $session = $cache->get($p->{'session_id'})
96     or return { 'error' => "Can't resume session" }; #better error message
97
98   #my %return;
99
100   my $agentnum = $session->{'agentnum'};
101
102   my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } )
103     or return { 'error' => "unknown agentnum $agentnum" };
104
105   my @cust_main = ();
106
107   #warn $p->{'search'};
108   if ( $p->{'search'} =~ /^\s*(\d+)\s*$/ ) { # customer # search
109     push @cust_main, qsearch('cust_main', { 'agentnum' => $agentnum,
110                                             'custnum'  => $1         } );
111   } elsif ( $p->{'search'} =~ /^\s*(\S.*\S)\s*$/ ) { #value search
112     my $value = lc($1);
113     my $q_value = dbh->quote($value);
114
115     #exact
116     my $sql = " AND ( LOWER(last) = $q_value OR LOWER(company) = $q_value";
117     $sql .= " OR LOWER(ship_last) = $q_value OR LOWER(ship_company) = $q_value"
118       if defined dbdef->table('cust_main')->column('ship_last');
119     $sql .= ' )';
120
121     push @cust_main, qsearch( 'cust_main',
122                               { 'agentnum' => $agentnum },
123                               '',
124                               $sql
125                             );
126
127     unless ( @cust_main ) {
128       warn "no exact match, trying substring/fuzzy\n";
129
130       #still some false laziness w/ search/cust_main.cgi
131
132       #substring
133       push @cust_main, qsearch( 'cust_main',
134                                 { 'agentnum' => $agentnum,
135                                   'last'     => { 'op'    => 'ILIKE',
136                                                   'value' => "%$q_value%" } } );
137
138       push @cust_main, qsearch( 'cust_main',
139                                 { 'agentnum'  => $agentnum,
140                                   'ship_last' => { 'op'    => 'ILIKE',
141                                                    'value' => "%$q_value%" } } )
142         if defined dbdef->table('cust_main')->column('ship_last');
143
144       push @cust_main, qsearch( 'cust_main',
145                                 { 'agentnum' => $agentnum,
146                                   'company'  => { 'op'    => 'ILIKE',
147                                                   'value' => "%$q_value%" } } );
148
149       push @cust_main, qsearch( 'cust_main',
150                                 { 'agentnum'     => $agentnum,
151                                   'ship_company' => { 'op' => 'ILIKE',
152                                                    'value' => "%$q_value%" } } )
153         if defined dbdef->table('cust_main')->column('ship_last');
154
155       #fuzzy
156       push @cust_main, FS::cust_main->fuzzy_search(
157         { 'last'     => $value },
158         { 'agentnum' => $agentnum }
159       );
160       push @cust_main, FS::cust_main->fuzzy_search(
161         { 'company'  => $value },
162         { 'agentnum' => $agentnum }
163       );
164
165     }
166   }
167
168   #aggregate searches
169   push @cust_main,
170     map $agent->$_(), map $_.'_cust_main',
171       grep $p->{$_}, qw( prospect active susp cancel );
172
173   #eliminate dups?
174   my %saw = ();
175   @cust_main = grep { !$saw{$_->custnum}++ } @cust_main;
176
177   { customers => [ map {
178                          my $cust_main = $_;
179                          my $hashref = $cust_main->hashref;
180                          $hashref->{$_} = $cust_main->$_()
181                            foreach qw(name status statuscolor);
182                          delete $hashref->{$_} foreach qw( payinfo paycvv );
183                          $hashref;
184                    } @cust_main
185                  ],
186   }
187
188 }
189