=cut
-#some false laziness w/ClientAPI::Myaccount customer_info/customer_info_short
-
-use vars qw( @cust_main_editable_fields @location_editable_fields );
-@cust_main_editable_fields = qw(
- first last company daytime night fax mobile
-);
-# locale
-# payby payinfo payname paystart_month paystart_year payissue payip
-# ss paytype paystate stateid stateid_state
-@location_editable_fields = qw(
- address1 address2 city county state zip country
-);
-
sub customer_info {
my( $class, %opt ) = @_;
my $conf = new FS::Conf;
my $cust_main = qsearchs('cust_main', { 'custnum' => $opt{custnum} })
or return { 'error' => 'Unknown custnum' };
- my %return = (
- 'error' => '',
- 'display_custnum' => $cust_main->display_custnum,
- 'name' => $cust_main->first. ' '. $cust_main->get('last'),
- 'balance' => $cust_main->balance,
- 'status' => $cust_main->status,
- 'statuscolor' => $cust_main->statuscolor,
- );
-
- $return{$_} = $cust_main->get($_)
- foreach @cust_main_editable_fields;
-
- for (@location_editable_fields) {
- $return{$_} = $cust_main->bill_location->get($_)
- if $cust_main->bill_locationnum;
- $return{'ship_'.$_} = $cust_main->ship_location->get($_)
- if $cust_main->ship_locationnum;
- }
-
- my @invoicing_list = $cust_main->invoicing_list;
- $return{'invoicing_list'} =
- join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list );
- $return{'postal_invoicing'} =
- 0 < ( grep { $_ eq 'POST' } @invoicing_list );
-
- #generally, the more useful data from the cust_main record the better.
- # well, tell me what you want
-
- return \%return;
+ $cust_main->API_getinfo;
}
-
=item location_info
Returns location specific information for the customer. Takes a hash reference as parameter with the following keys: custnum,secret
use FS::UI::Web qw(svc_url);
use FS::UI::Web::small_custview qw(small_custview);
use FS::UI::bytecount;
+ use FS::UI::REST qw( rest_auth rest_uri_remain encode_rest );
use FS::Msgcat qw(gettext geterror);
use FS::Misc qw( send_email send_fax ocr_image
states_hash counties cities state_label
my @bind_type = ();
my $dbh = dbh;
foreach my $stable ( @stable ) {
+
+ carp '->qsearch on cust_main called' if $stable eq 'cust_main' && $DEBUG;
+
#stop altering the caller's hashref
my $record = { %{ shift(@record) || {} } };#and be liberal in receipt
my $select = shift @select;
eval "use FS::$table";
die $@ if $@;
+ carp '->cust_main called' if $table eq 'cust_main' && $DEBUG;
+
my $pkey_value = $self->$column();
my %search = ( $foreign_column => $pkey_value );
$self->{'Hash'};
}
+#fallback
+sub API_getinfo {
+ my $self = shift;
+ +{ ( map { $_=>$self->$_ } $self->fields ),
+ };
+}
+
=item modified
Returns true if any of this object's values have been modified with set (or via
--- /dev/null
+package FS::UI::REST;
+use base qw( Exporter );
+
+use strict;
+use vars qw( @EXPORT_OK );
+use JSON::XS;
+use FS::UID qw( adminsuidsetup );
+use FS::Conf;
+
+@EXPORT_OK = qw( rest_auth rest_uri_remain encode_rest );
+
+sub rest_auth {
+ my $cgi = shift;
+ adminsuidsetup('fs_api');
+ my $conf = new FS::Conf;
+ die 'Incorrect shared secret'
+ unless $cgi->param('secret') eq $conf->config('api_shared_secret');
+}
+
+sub rest_uri_remain {
+ my($r, $m) = @_;
+
+ #wacky way to get this... surely there must be a better way
+
+ my $path = $m->request_comp->path;
+
+ $r->uri =~ /\Q$path\E\/?(.*)$/ or die "$path not in ". $r->uri;
+
+ $1;
+
+}
+
+sub encode_rest {
+ #XXX HTTP Accept header to send other formats besides JSON
+ encode_json(shift);
+}
+
+1;
}
+sub API_getinfo {
+ my $self = shift;
+ +{ ( map { $_=>$self->$_ } $self->fields ),
+ 'owed' => $self->owed,
+ #XXX last payment applied date
+ };
+}
+
=back
=head1 CLASS METHODS
FS::cust_main::Billing_ThirdParty
FS::cust_main::Location
FS::cust_main::Credit_Limit
+ FS::cust_main::API
FS::otaker_Mixin FS::payinfo_Mixin FS::cust_main_Mixin
FS::geocode_Mixin FS::Quotable_Mixin FS::Sales_Mixin
FS::o2m_Common
--- /dev/null
+package FS::cust_main::API;
+
+use strict;
+
+#some false laziness w/ClientAPI::Myaccount customer_info/customer_info_short
+
+use vars qw(
+ @cust_main_addl_fields @cust_main_editable_fields @location_editable_fields
+);
+@cust_main_addl_fields = qw(
+ agentnum salesnum refnum classnum usernum referral_custnum
+);
+@cust_main_editable_fields = qw(
+ first last company daytime night fax mobile
+);
+# locale
+# payby payinfo payname paystart_month paystart_year payissue payip
+# ss paytype paystate stateid stateid_state
+@location_editable_fields = qw(
+ address1 address2 city county state zip country
+);
+
+sub API_getinfo {
+ my( $self, %opt ) = @_;
+
+ my %return = (
+ 'error' => '',
+ 'display_custnum' => $self->display_custnum,
+ 'name' => $self->first. ' '. $self->get('last'),
+ 'balance' => $self->balance,
+ 'status' => $self->status,
+ 'statuscolor' => $self->statuscolor,
+ );
+
+ $return{$_} = $self->get($_)
+ foreach @cust_main_editable_fields;
+
+ unless ( $opt{'selfservice'} ) {
+ $return{$_} = $self->get($_)
+ foreach @cust_main_addl_fields;
+ }
+
+ for (@location_editable_fields) {
+ $return{$_} = $self->bill_location->get($_)
+ if $self->bill_locationnum;
+ $return{'ship_'.$_} = $self->ship_location->get($_)
+ if $self->ship_locationnum;
+ }
+
+ my @invoicing_list = $self->invoicing_list;
+ $return{'invoicing_list'} =
+ join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list );
+ $return{'postal_invoicing'} =
+ 0 < ( grep { $_ eq 'POST' } @invoicing_list );
+
+ #generally, the more useful data from the cust_main record the better.
+ # well, tell me what you want
+
+ return \%return;
+
+}
+
+1;
}
+sub API_getinfo {
+ my $self = shift;
+ my @fields = grep { $_ ne 'payinfo' } $self->fields;
+ +{ ( map { $_=>$self->$_ } @fields ),
+ };
+}
+
# _upgrade_data
#
# Used by FS::Upgrade to migrate to a new database.
package FS::cust_pkg;
-use base qw( FS::cust_pkg::Search
+use base qw( FS::cust_pkg::Search FS::cust_pkg::API
FS::otaker_Mixin FS::cust_main_Mixin FS::Sales_Mixin
FS::contact_Mixin FS::location_Mixin
FS::m2m_Common FS::option_Common
--- /dev/null
+package FS::cust_pkg::API;
+
+use strict;
+
+sub API_getinfo {
+ my $self = shift;
+
+ +{ ( map { $_=>$self->$_ } $self->fields ),
+ };
+
+}
+
+1;
(@tickets);
}
+sub API_getinfo {
+ my $self = shift;
+ my $svc_x = $self->svc_x;
+ +{ ( map { $_=>$self->$_ } $self->fields ),
+ ( map { $svc_x=>$svc_x->$_ } $svc_x->fields ),
+ };
+}
=back
})
];
- } elsif ( $opt{'state'} ) { #return aracodes
+ } elsif ( $opt{'state'} ) { #return areacodes
$hash{state} = $opt{state};
];
} else {
- die "FS::part_export::internal_diddb::get_dids called without options\n";
+
+ #die "FS::part_export::internal_diddb::get_dids called without options\n";
+ return [ map { $_->npa. '-'. $_->nxx. '-'. $_->station }
+ qsearch({ 'table' => 'phone_avail',
+ 'hashref' => \%hash,
+ 'order_by' => 'ORDER BY station',
+ })
+ ];
+
}
}
package FS::part_pkg;
-use base qw( FS::m2m_Common FS::o2m_Common FS::option_Common );
+use base qw( FS::part_pkg::API
+ FS::m2m_Common FS::o2m_Common FS::option_Common
+ );
use strict;
use vars qw( %plans $DEBUG $setup_hack $skip_pkg_svc_hack );
#false laziness w/part_export & cdr
my %info;
foreach my $INC ( @INC ) {
- warn "globbing $INC/FS/part_pkg/*.pm\n" if $DEBUG;
- foreach my $file ( glob("$INC/FS/part_pkg/*.pm") ) {
+ warn "globbing $INC/FS/part_pkg/[a-z]*.pm\n" if $DEBUG;
+ foreach my $file ( glob("$INC/FS/part_pkg/[a-z]*.pm") ) {
warn "attempting to load plan info from $file\n" if $DEBUG;
$file =~ /\/(\w+)\.pm$/ or do {
warn "unrecognized file in $INC/FS/part_pkg/: $file\n";
--- /dev/null
+package FS::part_pkg::API;
+
+use strict;
+
+sub API_getinfo {
+ my $self = shift;
+ #my( $self, %opt ) = @_;
+
+ +{ ( map { $_=>$self->$_ } $self->fields ),
+ ( map { $_=>$self->option($_) }
+ qw(setup_fee recur_fee)
+ ),
+ };
+
+}
+
+1;
PerlModule Apache2::compat
+PerlModule DBIx::Profile
#PerlModule Apache::DBI
PerlModule HTML::Mason
<Directory %%%FREESIDE_DOCUMENT_ROOT%%%/rt/REST/1.0/NoAuth/>
Satisfy any
</Directory>
+
+<Directory %%%FREESIDE_DOCUMENT_ROOT%%%/REST/>
+ Satisfy any
+ SetHandler perl-script
+ PerlHandler HTML::Mason
+</Directory>
Satisfy any
</Directory>
+<Directory %%%FREESIDE_DOCUMENT_ROOT%%%/REST/1.0/>
+ Satisfy any
+ SetHandler perl-script
+ PerlHandler HTML::Mason
+</Directory>
+
--- /dev/null
+<% encode_rest($return) %>\
+<%init>
+
+rest_auth($cgi);
+
+my( $invnum, $command ) = split('/', rest_uri_remain($r, $m) );
+
+my $cust_bill = qsearchs('cust_bill', { 'invnum'=>$invnum } )
+ or die "unknown invnum $invnum";
+
+my $return = [];
+
+if ( $command eq '' ) {
+
+ my @fields = fields('cust_bill');
+ $return = +{ map { $_=>$cust_bill->$_ } @fields };
+
+} elsif ( $command eq 'cust_bill_pkg' ) {
+
+ my @fields = fields('cust_bill_pkg');
+ $return = [ map { my $cust_bill_pkg = $_;
+ +{ map { $_=>$cust_bill_pkg->$_ } @fields };
+ }
+ $cust_bill->cust_bill_pkg
+ ];
+}
+
+</%init>
--- /dev/null
+<% encode_rest($return) %>\
+<%init>
+
+rest_auth($cgi);
+
+my( $custnum, $command ) = split('/', rest_uri_remain($r, $m), 2 );
+
+if ( $r->method eq 'GET' ) {
+
+ my $return = [];
+
+ if ( $custnum ) {
+
+ my $cust_main = qsearchs('cust_main', { 'custnum'=>$custnum } )
+ or die "unknown custnum $custnum";
+
+ if ( $command eq '' ) {
+
+ $return = $cust_main->API_getinfo;
+
+ } elsif ( $command =~ /^(cust_(pkg|attachment|bill|pay))$/ ) {
+
+ my $method = $1;
+
+ $return = [ map $_->API_getinfo, $cust_main->$method ];
+
+ } elsif ( $command eq 'part_pkg' ) {
+
+ my %pkgpart = map { $_->pkgpart => 1 } $cust_main->cust_pkg;
+
+ $return = [ map $_->API_getinfo,
+ map qsearchs('part_pkg', { 'pkgpart'=>$_ }),
+ keys %pkgpart;
+ ];
+
+ }
+
+ } else { #list
+
+ my %hash = ( map { $_ => scalar($cgi->param($_)) }
+ qw( agentnum salesnum refnum classnum usernum
+ referral_custnum
+ )
+ );
+
+ my $extra_sql = '';
+ if ( $cgi->param('cust_main_invoice_dest') ) {
+ my $dest = dbh->quote(scalar($cgi->param('cust_main_invoice_dest')));
+ $extra_sql = "
+ WHERE EXISTS ( SELECT 1 FROM cust_main_invoice
+ WHERE cust_main.custnum = cust_main_invoice.custnum
+ AND dest = $dest
+ )
+ ";
+ } elsif ( $cgi->param('cust_main_invoice_dest_substring') ) {
+ my $dest = dbh->quote('%'. scalar($cgi->param('cust_main_invoice_dest_substring')). '%');
+ $extra_sql = "
+ WHERE EXISTS ( SELECT 1 FROM cust_main_invoice
+ WHERE cust_main.custnum = cust_main_invoice.custnum
+ AND dest ILIKE $dest
+ )
+ ";
+ }
+
+ my @cust_main = qsearch({
+ 'table' => 'cust_main',
+ 'hashref' => \%hash,
+ 'extra_sql' => $extra_sql;
+ });
+
+ $return = [ map $_->API_getinfo, @cust_main ];
+
+ }
+
+} elsif ( $r->method eq 'POST' ) { #create new
+
+} elsif ( $r->method eq 'PUT' ) { #modify
+
+}
+
+</%init>
--- /dev/null
+<% encode_rest($return) %>\
+<%init>
+
+rest_auth($cgi);
+
+my( $pkgnum, $command ) = split('/', rest_uri_remain($r, $m), 2 );
+
+if ( $r->method eq 'GET' ) {
+
+ my $return = [];
+
+ if ( $pkgnum ) {
+
+ my $cust_pkg = qsearchs('cust_main', { 'pkgnum'=>$pkgnum } )
+ or die "unknown pkgnum $pkgnum";
+
+ if ( $command eq '' ) {
+
+ $return = $cust_pkg->API_getinfo;
+
+ } elsif ( $command eq 'cust_svc' ) {
+
+ $return = [ map $_->API_getinfo, $cust_pkg->cust_svc ];
+
+ }
+
+
+
+ #} else { #list
+
+ }
+
+} elsif ( $r->method eq 'POST' ) { #create new
+
+} elsif ( $r->method eq 'PUT' ) { #modify
+
+}
+
+</%init>
--- /dev/null
+<% encode_rest($return) %>\
+<%init>
+
+rest_auth($cgi);
+
+my( $pkgpart, $command ) = split('/', rest_uri_remain($r, $m) );
+
+my @fields = fields('part_pkg');
+
+my $return = [];
+
+if ( $pkgpart ) {
+
+ my $part_pkg = qsearchs('part_pkg', { 'pkgpart'=>$pkgpart } )
+ or die "unknown pkgpart $pkgpart";
+
+ if ( $command eq '' ) {
+
+ $return = $part_pkg->API_getinfo;
+
+ } elsif ( $command eq 'customers' ) {
+ die 'XXX not yet implemented';
+ #XXX redirect to a cust_main search?
+ }
+
+} else {
+
+ my %hash = ( map { $_ => scalar($cgi->param($_)) }
+ qw( disabled classnum )
+ );
+
+ my @part_pkg = qsearch('part_pkg', \%hash);
+
+ $return = [ map $part_pkg->API_getinfo, @part_pkg ];
+
+}
+
+
+
+</%init>
--- /dev/null
+<% encode_rest($phonenums) %>\
+<%init>
+
+rest_auth($cgi);
+
+#i'm basically a simpler misc/phonenums.cgi
+
+my $svcpart = $cgi->param('svcpart');
+
+my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } );
+die "unknown svcpart $svcpart" unless $part_svc;
+
+my @exports = $part_svc->part_export_did;
+if ( scalar(@exports) > 1 ) {
+ die "more than one DID-providing export attached to svcpart $svcpart";
+} elsif ( ! @exports ) {
+ die "no DID providing export attached to svcpart $svcpart";
+}
+my $export = $exports[0];
+
+my $phonenums = $export->get_dids( map { $_ => scalar($cgi->param($_)) }
+ qw( ratecenter state areacode exchange )
+ );
+
+</%init>
--- /dev/null
+<% encode_rest( \@rate_detail ) %>\
+<%init>
+
+rest_auth($cgi);
+
+my $extra_sql = '';
+if ( $cgi->param('countrycode') =~ /^\+?(\d+)$/ ) {
+ my $countrycode = $1;
+ $extra_sql = "
+ WHERE EXISTS ( SELECT 1 rate_region
+ WHERE rate_detail.dest_regionnum = rate_region.regionnum
+ AND countrycode = '$countrycode'
+ ";
+}
+
+my @detail_fields = fields('rate_detail');
+my @region_fields = fields('rate_region');
+
+my @rate_detail =
+ map {
+ my $rate_detail = $_;
+ my $rate_region = $rate_detail->dest_region;
+
+ +{
+ ( map { $_ => $rate_detail->$_ } @detail_fields ),
+ ( map { $_ => $rate_region->$_ } @region_fields ),
+ };
+
+ } qsearch({
+ 'table' => 'rate_detail',
+ 'hashref' => {},
+ extra_sql => $extra_sql,
+ });
+
+</%init>