add a domain pulldown to svc_acct linking, closes: Bug#277 / prevent "stealing" servi...
[freeside.git] / FS / FS / part_export / infostreet.pm
1 package FS::part_export::infostreet;
2
3 use vars qw(@ISA %info %infostreet2cust_main $DEBUG);
4 use Tie::IxHash;
5 use FS::UID qw(dbh);
6 use FS::part_export;
7
8 @ISA = qw(FS::part_export);
9
10 tie my %options, 'Tie::IxHash',
11   'url'      => { label=>'XML-RPC Access URL', },
12   'login'    => { label=>'InfoStreet login', },
13   'password' => { label=>'InfoStreet password', },
14   'groupID'  => { label=>'InfoStreet groupID', },
15 ;
16
17 %info = (
18   'svc'      => 'svc_acct',
19   'desc'     => 'Real-time export to InfoStreet streetSmartAPI',
20   'options'  => \%options,
21   'nodomain' => 'Y',
22   'notes'    => <<'END'
23 Real-time export to
24 <a href="http://www.infostreet.com/">InfoStreet</a> streetSmartAPI.
25 Requires installation of
26 <a href="http://search.cpan.org/dist/Frontier-Client">Frontier::Client</a> from CPAN.
27 END
28 );
29
30 $DEBUG = 0;
31
32 %infostreet2cust_main = (
33   'firstName'   => 'first',
34   'lastName'    => 'last',
35   'address1'    => 'address1',
36   'address2'    => 'address2',
37   'city'        => 'city',
38   'state'       => 'state',
39   'zipCode'     => 'zip',
40   'country'     => 'country',
41   'phoneNumber' => 'daytime',
42   'faxNumber'   => 'night', #noment-request...
43 );
44
45 sub rebless { shift; }
46
47 sub _export_insert {
48   my( $self, $svc_acct ) = (shift, shift);
49   my $cust_main = $svc_acct->cust_svc->cust_pkg->cust_main;
50
51   local $SIG{HUP} = 'IGNORE';
52   local $SIG{INT} = 'IGNORE';
53   local $SIG{QUIT} = 'IGNORE';
54   local $SIG{TERM} = 'IGNORE';
55   local $SIG{TSTP} = 'IGNORE';
56   local $SIG{PIPE} = 'IGNORE';
57   my $oldAutoCommit = $FS::UID::AutoCommit;
58   local $FS::UID::AutoCommit = 0;
59   my $dbh = dbh;
60
61   my $err_or_queue = $self->infostreet_err_or_queue( $svc_acct->svcnum,
62     'createUser', $svc_acct->username, $svc_acct->_password );
63   return $err_or_queue unless ref($err_or_queue);
64   my $jobnum = $err_or_queue->jobnum;
65
66   my %contact_info = ( map {
67     $_ => $cust_main->getfield( $infostreet2cust_main{$_} );
68   } keys %infostreet2cust_main );
69
70   my @emails = grep { $_ ne 'POST' } $cust_main->invoicing_list;
71   $contact_info{'email'} = $emails[0] if @emails;
72
73   #this one is kinda noment-specific
74   $contact_info{'organization'} = $cust_main->agent->agent;
75
76   $err_or_queue = $self->infostreet_queueContact( $svc_acct->svcnum,
77     $svc_acct->username, %contact_info );
78   return $err_or_queue unless ref($err_or_queue);
79
80   # If a quota has been specified set the quota because it is not the default
81   $err_or_queue = $self->infostreet_queueSetQuota( $svc_acct->svcnum, 
82     $svc_acct->username, $svc_acct->quota ) if $svc_acct->quota;
83   return $err_or_queue unless ref($err_or_queue);
84
85   my $error = $err_or_queue->depend_insert( $jobnum );
86   return $error if $error;
87
88   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
89
90   '';
91
92 }
93
94 sub _export_replace {
95   my( $self, $new, $old ) = (shift, shift, shift);
96   return "can't change username with InfoStreet"
97     if $old->username ne $new->username;
98
99   # If the quota has changed then do the export to setQuota
100   my $err_or_queue = $self->infostreet_queueSetQuota( $new->svcnum, $new->username, $new->quota ) 
101         if ( $old->quota != $new->quota );  
102   return $err_or_queue unless ref($err_or_queue);
103
104
105   return '' unless $old->_password ne $new->_password;
106   $self->infostreet_queue( $new->svcnum,
107     'passwd', $new->username, $new->_password );
108 }
109
110 sub _export_delete {
111   my( $self, $svc_acct ) = (shift, shift);
112   $self->infostreet_queue( $svc_acct->svcnum,
113     'purgeAccount,releaseUsername', $svc_acct->username );
114 }
115
116 sub _export_suspend {
117   my( $self, $svc_acct ) = (shift, shift);
118   $self->infostreet_queue( $svc_acct->svcnum,
119     'setStatus', $svc_acct->username, 'DISABLED' );
120 }
121
122 sub _export_unsuspend {
123   my( $self, $svc_acct ) = (shift, shift);
124   $self->infostreet_queue( $svc_acct->svcnum,
125     'setStatus', $svc_acct->username, 'ACTIVE' );
126 }
127
128 sub infostreet_queue {
129   my( $self, $svcnum, $method ) = (shift, shift, shift);
130   my $queue = new FS::queue {
131     'svcnum' => $svcnum,
132     'job'    => 'FS::part_export::infostreet::infostreet_command',
133   };
134   $queue->insert(
135     $self->option('url'),
136     $self->option('login'),
137     $self->option('password'),
138     $self->option('groupID'),
139     $method,
140     @_,
141   );
142 }
143
144 #ick false laziness
145 sub infostreet_err_or_queue {
146   my( $self, $svcnum, $method ) = (shift, shift, shift);
147   my $queue = new FS::queue {
148     'svcnum' => $svcnum,
149     'job'    => 'FS::part_export::infostreet::infostreet_command',
150   };
151   $queue->insert(
152     $self->option('url'),
153     $self->option('login'),
154     $self->option('password'),
155     $self->option('groupID'),
156     $method,
157     @_,
158   ) or $queue;
159 }
160
161 sub infostreet_queueContact {
162   my( $self, $svcnum ) = (shift, shift);
163   my $queue = new FS::queue {
164     'svcnum' => $svcnum,
165     'job'    => 'FS::part_export::infostreet::infostreet_setContact',
166   };
167   $queue->insert(
168     $self->option('url'),
169     $self->option('login'),
170     $self->option('password'),
171     $self->option('groupID'),
172     @_,
173   ) or $queue;
174 }
175
176 sub infostreet_setContact {
177   my($url, $is_username, $is_password, $groupID, $username, %contact_info) = @_;
178   my $accountID = infostreet_command($url, $is_username, $is_password, $groupID,
179     'getAccountID', $username);
180   foreach my $field ( keys %contact_info ) {
181     infostreet_command($url, $is_username, $is_password, $groupID,
182       'setContactField', [ 'int'=>$accountID ], $field, $contact_info{$field} );
183   }
184
185 }
186
187 sub infostreet_queueSetQuota {
188
189  my( $self, $svcnum) = (shift, shift);
190  my $queue = new FS::queue {
191     'svcnum' => $svcnum,
192     'job'    => 'FS::part_export::infostreet::infostreet_setQuota',
193  };
194
195  $queue->insert(
196     $self->option('url'),
197     $self->option('login'),
198     $self->option('password'),
199     $self->option('groupID'),
200     @_,
201  ) or $queue;
202
203 }
204
205 sub infostreet_setQuota {
206   my($url, $is_username, $is_password, $groupID, $username, $quota) = @_;
207   infostreet_command($url, $is_username, $is_password, $groupID, 'setQuota', $username, [ 'int'=> $quota ]  );
208 }
209
210
211 sub infostreet_command { #subroutine, not method
212   my($url, $username, $password, $groupID, $method, @args) = @_;
213
214   warn "[FS::part_export::infostreet] $method ".join(' ', @args)."\n" if $DEBUG;
215
216   #quelle hack
217   if ( $method =~ /,/ ) {
218     foreach my $part ( split(/,\s*/, $method) ) {
219       infostreet_command($url, $username, $password, $groupID, $part, @args);
220     }
221     return;
222   }
223
224   eval "use Frontier::Client;";
225   die $@ if $@;
226
227   eval 'sub Frontier::RPC2::String::repr {
228     my $self = shift;
229     my $value = $$self;
230     $value =~ s/([&<>\"])/$Frontier::RPC2::char_entities{$1}/ge;
231     $value;
232   }';
233   die $@ if $@;
234
235   my $conn = Frontier::Client->new( url => $url );
236   my $key_result = $conn->call( 'authenticate', $username, $password, $groupID);
237   my %key_result = _infostreet_parse($key_result);
238   die $key_result{error} unless $key_result{success};
239   my $key = $key_result{data};
240
241   #my $result = $conn->call($method, $key, @args);
242   my $result = $conn->call( $method, $key,
243                             map {
244                                   if ( ref($_) ) {
245                                     my( $type, $value) = @{$_};
246                                     $conn->$type($value);
247                                   } else {
248                                     $conn->string($_);
249                                   }
250                                 } @args );
251   my %result = _infostreet_parse($result);
252   die $result{error} unless $result{success};
253
254   $result->{data};
255
256 }
257
258 #sub infostreet_command_byid { #subroutine, not method;
259 #  my($url, $username, $password, $groupID, $method, @args ) = @_;
260 #
261 #  infostreet_command
262 #
263 #}
264
265 sub _infostreet_parse { #subroutine, not method
266   my $arg = shift;
267   map {
268     my $value = $arg->{$_};
269     #warn ref($value);
270     $value = $value->value()
271       if ref($value) && $value->isa('Frontier::RPC2::DataType');
272     $_=>$value;
273   } keys %$arg;
274 }
275
276 1;
277