4 use FS::Record qw( qsearchs );
12 FS::API - Freeside backend API
20 This module implements a backend API for advanced back-office integration.
22 In contrast to the self-service API, which authenticates an end-user and offers
23 functionality to that end user, the backend API performs a simple shared-secret
24 authentication and offers full, administrator functionality, enabling
25 integration with other back-office systems.
27 If accessing this API remotely with XML-RPC or JSON-RPC, be careful to block
28 the port by default, only allow access from back-office servers with the same
29 security precations as the Freeside server, and encrypt the communication
30 channel (for exampple, with an SSH tunnel or VPN) rather than accessing it
41 my $result = FS::API->insert_payment(
42 'secret' => 'sharingiscaring',
48 '_date' => 1397977200, #UNIX timestamp
51 if ( $result->{'error'} ) {
52 die $result->{'error'};
55 print "paynum ". $result->{'paynum'};
62 my($class, %opt) = @_;
63 my $conf = new FS::Conf;
64 return { 'error' => 'Incorrect shared secret' }
65 unless $opt{secret} eq $conf->config('api_shared_secret');
67 #less "raw" than this? we are the backoffice API, and aren't worried
68 # about version migration ala cust_main/cust_location here
69 my $cust_pay = new FS::cust_pay { %opt };
70 my $error = $cust_pay->insert( 'manual'=>1 );
71 return { 'error' => $error,
72 'paynum' => $cust_pay->paynum,
76 # pass the phone number ( from svc_phone )
77 sub insert_payment_phonenum {
78 my($class, %opt) = @_;
79 my $conf = new FS::Conf;
80 return { 'error' => 'Incorrect shared secret' }
81 unless $opt{secret} eq $conf->config('api_shared_secret');
83 $class->_by_phonenum('insert_payment', %opt);
88 my($class, $method, %opt) = @_;
89 my $conf = new FS::Conf;
90 return { 'error' => 'Incorrect shared secret' }
91 unless $opt{secret} eq $conf->config('api_shared_secret');
93 my $phonenum = delete $opt{'phonenum'};
95 my $svc_phone = qsearchs('svc_phone', { 'phonenum' => $phonenum } )
96 or return { 'error' => 'Unknown phonenum' };
98 my $cust_pkg = $svc_phone->cust_svc->cust_pkg
99 or return { 'error' => 'Unlinked phonenum' };
101 $opt{'custnum'} = $cust_pkg->custnum;
103 $class->$method(%opt);
111 my $result = FS::API->insert_credit(
112 'secret' => 'sharingiscaring',
117 '_date' => 1397977200, #UNIX timestamp
120 if ( $result->{'error'} ) {
121 die $result->{'error'};
124 print "crednum ". $result->{'crednum'};
131 my($class, %opt) = @_;
132 my $conf = new FS::Conf;
133 return { 'error' => 'Incorrect shared secret' }
134 unless $opt{secret} eq $conf->config('api_shared_secret');
136 $opt{'reasonnum'} ||= $conf->config('api_credit_reason');
138 #less "raw" than this? we are the backoffice API, and aren't worried
139 # about version migration ala cust_main/cust_location here
140 my $cust_credit = new FS::cust_credit { %opt };
141 my $error = $cust_credit->insert;
142 return { 'error' => $error,
143 'crednum' => $cust_credit->crednum,
147 # pass the phone number ( from svc_phone )
148 sub insert_credit_phonenum {
149 my($class, %opt) = @_;
150 my $conf = new FS::Conf;
151 return { 'error' => 'Incorrect shared secret' }
152 unless $opt{secret} eq $conf->config('api_shared_secret');
154 $class->_by_phonenum('insert_credit', %opt);
162 my $result = FS::API->insert_refund(
163 'secret' => 'sharingiscaring',
169 '_date' => 1397977200, #UNIX timestamp
172 if ( $result->{'error'} ) {
173 die $result->{'error'};
176 print "refundnum ". $result->{'crednum'};
183 my($class, %opt) = @_;
184 my $conf = new FS::Conf;
185 return { 'error' => 'Incorrect shared secret' }
186 unless $opt{secret} eq $conf->config('api_shared_secret');
188 # when github pull request #24 is merged,
189 # will have to change over to default reasonnum like credit
190 # but until then, this will do
191 $opt{'reason'} ||= 'API refund';
193 #less "raw" than this? we are the backoffice API, and aren't worried
194 # about version migration ala cust_main/cust_location here
195 my $cust_refund = new FS::cust_refund { %opt };
196 my $error = $cust_refund->insert;
197 return { 'error' => $error,
198 'refundnum' => $cust_refund->refundnum,
202 # pass the phone number ( from svc_phone )
203 sub insert_refund_phonenum {
204 my($class, %opt) = @_;
205 my $conf = new FS::Conf;
206 return { 'error' => 'Incorrect shared secret' }
207 unless $opt{secret} eq $conf->config('api_shared_secret');
209 $class->_by_phonenum('insert_refund', %opt);
217 # The fields needed are:
230 # cust_main_invoice.dest
236 #Advertising sources?
238 # "2 way syncing" ? start with non-sync pulling info here, then if necessary
239 # figure out how to trigger something when those things change
241 # long-term: package changes?
247 #some false laziness w/ClientAPI::Myaccount customer_info/customer_info_short
249 use vars qw( @cust_main_editable_fields @location_editable_fields );
250 @cust_main_editable_fields = qw(
251 first last company daytime night fax mobile
254 # payby payinfo payname paystart_month paystart_year payissue payip
255 # ss paytype paystate stateid stateid_state
256 @location_editable_fields = qw(
257 address1 address2 city county state zip country
261 my( $class, %opt ) = @_;
262 my $conf = new FS::Conf;
263 return { 'error' => 'Incorrect shared secret' }
264 unless $opt{secret} eq $conf->config('api_shared_secret');
266 my $cust_main = qsearchs('cust_main', { 'custnum' => $opt{custnum} })
267 or return { 'error' => 'Unknown custnum' };
271 'display_custnum' => $cust_main->display_custnum,
272 'name' => $cust_main->first. ' '. $cust_main->get('last'),
275 $return{$_} = $cust_main->get($_)
276 foreach @cust_main_editable_fields;