summaryrefslogtreecommitdiff
path: root/FS/FS/ClientAPI/Bulk.pm
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/ClientAPI/Bulk.pm')
-rw-r--r--FS/FS/ClientAPI/Bulk.pm384
1 files changed, 384 insertions, 0 deletions
diff --git a/FS/FS/ClientAPI/Bulk.pm b/FS/FS/ClientAPI/Bulk.pm
new file mode 100644
index 0000000..ec617df
--- /dev/null
+++ b/FS/FS/ClientAPI/Bulk.pm
@@ -0,0 +1,384 @@
+package FS::ClientAPI::Bulk;
+
+use strict;
+
+use vars qw( $DEBUG $cache );
+use Date::Parse;
+use FS::Record qw( qsearchs );
+use FS::Conf;
+use FS::ClientAPI_SessionCache;
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::cust_svc;
+use FS::svc_acct;
+use FS::svc_external;
+use FS::cust_recon;
+use Data::Dumper;
+
+$DEBUG = 1;
+
+sub _cache {
+ $cache ||= new FS::ClientAPI_SessionCache ( {
+ 'namespace' => 'FS::ClientAPI::Agent', #yes, share session_ids
+ } );
+}
+
+sub _izoom_ftp_row_fixup {
+ my $hash = shift;
+
+ my @addr_fields = qw( address1 address2 city state zip );
+ my @fields = ( qw( agent_custid username _password first last ),
+ @addr_fields,
+ map { "ship_$_" } @addr_fields );
+
+ $hash->{$_} =~ s/[&\/\*'"]/_/g foreach @fields;
+
+ #$hash->{action} = '' if $hash->{action} eq 'R'; #unsupported for ftp
+
+ $hash->{refnum} = 1; #ahem
+ $hash->{country} = 'US';
+ $hash->{ship_country} = 'US';
+ $hash->{payby} = 'LECB';
+ $hash->{payinfo} = $hash->{daytime};
+ $hash->{ship_fax} = '' if ( !$hash->{sms} || $hash->{sms} eq 'F' );
+
+ my $has_ship =
+ grep { $hash->{"ship_$_"} &&
+ (! $hash->{$_} || $hash->{"ship_$_"} ne $hash->{$_} )
+ }
+ ( @addr_fields, 'fax' );
+
+ if ( $has_ship ) {
+ foreach ( @addr_fields, qw( first last ) ) {
+ $hash->{"ship_$_"} = $hash->{$_} unless $hash->{"ship_$_"};
+ }
+ }
+
+ delete $hash->{sms};
+
+ '';
+
+};
+
+sub _izoom_ftp_result {
+ my ($hash, $error) = @_;
+ my $cust_main =
+ qsearchs( 'cust_main', { 'agent_custid' => $hash->{agent_custid},
+ 'agentnum' => $hash->{agentnum}
+ }
+ );
+
+ my $custnum = $cust_main ? $cust_main->custnum : '';
+ my @response = ( $hash->{action}, $hash->{agent_custid}, $custnum );
+
+ if ( $error ) {
+ push @response, ( 'ERROR', $error );
+ } else {
+ push @response, ( 'OK', 'OK' );
+ }
+
+ join( ',', @response );
+
+}
+
+sub _izoom_ftp_badaction {
+ "Invalid action: $_[0] record: @_ ";
+}
+
+sub _izoom_soap_row_fixup { _izoom_ftp_row_fixup(@_) };
+
+sub _izoom_soap_result {
+ my ($hash, $error) = @_;
+
+ if ( $hash->{action} eq 'R' ) {
+ if ( $error ) {
+ return "Please check errors:\n $error"; # odd extra space
+ } else {
+ return join(' ', "Everything ok.", $hash->{pkg}, $hash->{adjourn} );
+ }
+ }
+
+ my $pkg = $hash->{pkg} || $hash->{saved_pkg} || '';
+ if ( $error ) {
+ return join(' ', $hash->{agent_custid}, $error );
+ } else {
+ return join(' ', $hash->{agent_custid}, $pkg, $hash->{adjourn} );
+ }
+
+}
+
+sub _izoom_soap_badaction {
+ "Unknown action '$_[13]' ";
+}
+
+my %format = (
+ 'izoom-ftp' => {
+ 'fields' => [ qw ( action agent_custid username _password
+ daytime ship_fax sms first last
+ address1 address2 city state zip
+ pkg adjourn ship_address1 ship_address2
+ ship_city ship_state ship_zip ) ],
+ 'fixup' => sub { _izoom_ftp_row_fixup(@_) },
+ 'result' => sub { _izoom_ftp_result(@_) },
+ 'action' => sub { _izoom_ftp_badaction(@_) },
+ },
+ 'izoom-soap' => {
+ 'fields' => [ qw ( agent_custid username _password
+ daytime first last address1 address2
+ city state zip pkg action adjourn
+ ship_fax sms ship_address1 ship_address2
+ ship_city ship_state ship_zip ) ],
+ 'fixup' => sub { _izoom_soap_row_fixup(@_) },
+ 'result' => sub { _izoom_soap_result(@_) },
+ 'action' => sub { _izoom_soap_badaction(@_) },
+ },
+);
+
+sub processrow {
+ my $p = shift;
+
+ my $session = _cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $conf = new FS::Conf;
+ my $format = $conf->config('selfservice-bulk_format', $session->{agentnum})
+ || 'izoom-soap';
+ my ( @row ) = @{ $p->{row} };
+
+ warn "processrow called with '". join("' '", @row). "'\n" if $DEBUG;
+
+ return { 'error' => "unknown format: $format" }
+ unless exists $format{$format};
+
+ return { 'error' => "Invalid record record length: ". scalar(@row).
+ "record: @row " #sic
+ }
+ unless scalar(@row) == scalar(@{$format{$format}{fields}});
+
+ my %hash = ( 'agentnum' => $session->{agentnum} );
+ my $error;
+
+ foreach my $field ( @{ $format{ $format }{ fields } } ) {
+ $hash{$field} = shift @row;
+ }
+
+ $error ||= &{ $format{ $format }{ fixup } }( \%hash );
+
+ # put in the fixup routine?
+ if ( 'R' eq $hash{action} ) {
+ warn "processing reconciliation\n" if $DEBUG;
+ $error ||= process_recon($hash{agentnum}, $hash{agent_custid});
+ } elsif ( 'P' eq $hash{action} ) {
+ # do nothing
+ } elsif( 'D' eq $hash{action} ) {
+ $hash{promo_pkg} = 'disk-1-'. $session->{agent};
+ } elsif ( 'S' eq $hash{action} ) {
+ $hash{promo_pkg} = 'disk-2-'. $session->{agent};
+ $hash{saved_pkg} = $hash{pkg};
+ $hash{pkg} = '';
+ } else {
+ $error ||= &{ $format{ $format }{ action } }( @row );
+ }
+
+ warn "processing provision\n" if ($DEBUG && !$error && $hash{action} ne 'R');
+ $error ||= provision( %hash ) unless $hash{action} eq 'R';
+
+ my $result = &{ $format{ $format }{ result } }( \%hash, $error );
+
+ warn "processrow returning '". join("' '", $result, $error). "'\n"
+ if $DEBUG;
+
+ return { 'error' => $error, 'message' => $result };
+
+}
+
+sub provision {
+ my %args = ( @_ );
+
+ delete $args{action};
+
+ my $cust_main =
+ qsearchs( 'cust_main',
+ { map { $_ => $args{$_} } qw ( agent_custid agentnum ) },
+ );
+
+ unless ( $cust_main ) {
+ $cust_main = new FS::cust_main { %args };
+ my $error = $cust_main->insert;
+ return $error if $error;
+ }
+
+ my @pkgs = grep { $_->part_pkg->freq } $cust_main->ncancelled_pkgs;
+ if ( scalar(@pkgs) > 1 ) {
+ return "Invalid account, should not be more then one active package ". #sic
+ "but found: ". scalar(@pkgs). " packages.";
+ }
+
+ my $part_pkg = qsearchs( 'part_pkg', { 'pkg' => $args{pkg} } )
+ or return "Unknown pkgpart: $args{pkg}"
+ if $args{pkg};
+
+
+ my $create_package = $args{pkg};
+ if ( scalar(@pkgs) && $create_package ) {
+ my $pkg = pop(@pkgs);
+
+ if ( $part_pkg->pkgpart != $pkg->pkgpart ) {
+ my @cust_bill_pkg = $pkg->cust_bill_pkg();
+ if ( 1 == scalar(@cust_bill_pkg) ) {
+ my $cbp= pop(@cust_bill_pkg);
+ my $cust_bill = $cbp->cust_bill;
+ $cust_bill->delete(); #really? wouldn't a credit be better?
+ }
+ $pkg->cancel();
+ } else {
+ $create_package = '';
+ $pkg->setfield('adjourn', str2time($args{adjourn}));
+ my $error = $pkg->replace();
+ return $error if $error;
+ }
+ }
+
+ if ( $create_package ) {
+ my $cust_pkg = new FS::cust_pkg ( {
+ 'pkgpart' => $part_pkg->pkgpart,
+ 'adjourn' => str2time( $args{adjourn} ),
+ } );
+
+ my $svcpart = $part_pkg->svcpart('svc_acct');
+
+ my $svc_acct = new FS::svc_acct ( {
+ 'svcpart' => $svcpart,
+ 'username' => $args{username},
+ '_password' => $args{_password},
+ } );
+
+ my $error = $cust_main->order_pkg( cust_pkg => $cust_pkg,
+ svcs => [ $svc_acct ],
+ );
+ return $error if $error;
+ }
+
+ if ( $args{promo_pkg} ) {
+ my $part_pkg =
+ qsearchs( 'part_pkg', { 'promo_code' => $args{promo_pkg} } )
+ or return "unknown pkgpart: $args{promo_pkg}";
+
+ my $svcpart = $part_pkg->svcpart('svc_external')
+ or return "unknown svcpart: svc_external";
+
+ my $cust_pkg = new FS::cust_pkg ( {
+ 'svcpart' => $svcpart,
+ 'pkgpart' => $part_pkg->pkgpart,
+ } );
+
+ my $svc_ext = new FS::svc_external ( { 'svcpart' => $svcpart } );
+
+ my $ticket_subject = 'Send setup disk to customer '. $cust_main->custnum;
+ my $error = $cust_main->order_pkg ( cust_pkg => $cust_pkg,
+ svcs => [ $svc_ext ],
+ noexport => 1,
+ ticket_subject => $ticket_subject,
+ ticket_queue => "disk-$args{agentnum}",
+ );
+ return $error if $error;
+ }
+
+ my $error = $cust_main->bill();
+ return $error if $error;
+}
+
+sub process_recon {
+ my ( $agentnum, $id ) = @_;
+ my @recs = split /;/, $id;
+ my $err = '';
+ foreach my $rec ( @recs ) {
+ my @record = split /,/, $rec;
+ my $result = process_recon_record(@record, $agentnum);
+ $err .= "$result\n" if $result;
+ }
+ return $err;
+}
+
+sub process_recon_record {
+ my ( $agent_custid, $username, $_password, $daytime, $first, $last, $address1, $address2, $city, $state, $zip, $pkg, $adjourn, $agentnum) = @_;
+
+ warn "process_recon_record called with '". join("','", @_). "'\n" if $DEBUG;
+
+ my ($cust_pkg, $package);
+
+ my $cust_main =
+ qsearchs( 'cust_main',
+ { 'agent_custid' => $agent_custid, 'agentnum' => $agentnum },
+ );
+
+ my $comments = '';
+ if ( $cust_main ) {
+ my @cust_pkg = grep { $_->part_pkg->freq } $cust_main->ncancelled_pkgs;
+ if ( scalar(@cust_pkg) == 1) {
+ $cust_pkg = pop(@cust_pkg);
+ $package = $cust_pkg->part_pkg->pkg;
+ $comments = "$agent_custid wrong package, expected: $pkg found: $package"
+ if ( $pkg ne $package );
+ } else {
+ $comments = "invalid account, should be one active package but found: ".
+ scalar(@cust_pkg). " packages.";
+ }
+ } else {
+ $comments =
+ "Customer not found agent_custid=$agent_custid, agentnum=$agentnum";
+ }
+
+ my $cust_recon = new FS::cust_recon( {
+ 'recondate' => time,
+ 'agentnum' => $agentnum,
+ 'first' => $first,
+ 'last' => $last,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'custnum' => $cust_main ? $cust_main->custnum : '', #really?
+ 'status' => $cust_main ? $cust_main->status : '',
+ 'pkg' => $package,
+ 'adjourn' => $cust_pkg ? $cust_pkg->adjourn : '',
+ 'agent_custid' => $agent_custid, # redundant?
+ 'agent_pkg' => $pkg,
+ 'agent_adjourn' => str2time($adjourn),
+ 'comments' => $comments,
+ } );
+
+ warn Dumper($cust_recon) if $DEBUG;
+ my $error = $cust_recon->insert;
+ return $error if $error;
+
+ warn "process_recon_record returning $comments\n" if $DEBUG;
+
+ $comments;
+
+}
+
+sub check_username {
+ my $p = shift;
+
+ my $session = _cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $svc_domain = qsearchs( 'svc_domain', { 'domain' => $p->{domain} } )
+ or return { 'error' => 'Unknown domain '. $p->{domain} };
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'username' => $p->{user},
+ 'domsvc' => $svc_domain->svcnum,
+ },
+ );
+
+ return { 'error' => $p->{user}. '@'. $p->{domain}. " alerady in use" } # sic
+ if $svc_acct;
+
+ return { 'error' => '',
+ 'message' => $p->{user}. '@'. $p->{domain}. " is free"
+ };
+}
+
+1;