X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FSignup.pm;h=a4032f3b1f00f9caa05820d65acc965824fcde21;hp=aeb0aaac9d4bfe72fe840a33cb8ccde997f53f76;hb=3706609762d9cec964f337e74829031b895ddbac;hpb=3c4456c1de9701d93b64fcbadcfaca598a0347d8 diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index aeb0aaac9..a4032f3b1 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -1,11 +1,12 @@ package FS::ClientAPI::Signup; use strict; -use vars qw($DEBUG $me); +use vars qw( $DEBUG $me ); use Data::Dumper; use Tie::RefHash; use FS::Conf; use FS::Record qw(qsearch qsearchs dbdef); +use FS::CGI qw(popurl); use FS::Msgcat qw(gettext); use FS::Misc qw(card_types); use FS::ClientAPI_SessionCache; @@ -20,6 +21,7 @@ use FS::svc_phone; use FS::acct_snarf; use FS::queue; use FS::reg_code; +use FS::payby; $DEBUG = 0; $me = '[FS::ClientAPI::Signup]'; @@ -48,15 +50,22 @@ sub signup_info { my $agentnum2part_pkg = { map { - my $href = $_->pkgpart_hashref; - $_->agentnum => + my $agent = $_; + my $href = $agent->pkgpart_hashref; + $agent->agentnum => [ map { { 'payby' => [ $_->payby ], 'freq_pretty' => $_->freq_pretty, 'options' => { $_->options }, %{$_->hashref} } } - grep { $_->svcpart($svc_x) && $href->{ $_->pkgpart } } + grep { $_->svcpart($svc_x) + && ( $href->{ $_->pkgpart } + || ( $_->agentnum + && $_->agentnum == $agent->agentnum + ) + ) + } qsearch( 'part_pkg', { 'disabled' => '' } ) ]; } qsearch('agent', { 'disabled' => '' }) @@ -73,12 +82,16 @@ sub signup_info { }; warn "label: ". Dumper($label). "\n" if $DEBUG > 2; + my @agent_fields = qw( agentnum agent ); + $signup_info_cache = { 'cust_main_county' => [ map $_->hashref, qsearch('cust_main_county', {} ) ], - 'agent' => [ map $_->hashref, + 'agent' => [ map { my $agent = $_; + +{ map { $_ => $agent->get($_) } @agent_fields } + } qsearch('agent', { 'disabled' => '' } ) ], @@ -94,8 +107,13 @@ sub signup_info { 'security_phrase' => $conf->exists('security_phrase'), + 'nomadix' => $conf->exists('signup_server-nomadix'), + 'payby' => [ $conf->config('signup_server-payby') ], + 'payby_longname' => [ map { FS::payby->longname($_) } + $conf->config('signup_server-payby') ], + 'card_types' => card_types(), 'paytypes' => [ @FS::cust_main::paytypes ], @@ -123,6 +141,22 @@ sub signup_info { 'signup_service' => $svc_x, 'default_svcpart' => scalar($conf->config('signup_server-default_svcpart')), + 'head' => join("\n", $conf->config('selfservice-head') ), + 'body_header' => join("\n", $conf->config('selfservice-body_header') ), + 'body_footer' => join("\n", $conf->config('selfservice-body_footer') ), + 'body_bgcolor' => scalar( $conf->config('selfservice-body_bgcolor') ), + 'box_bgcolor' => scalar( $conf->config('selfservice-box_bgcolor') ), + + 'company_name' => scalar($conf->config('company_name')), + + #per-agent? + 'agent_ship_address' => scalar($conf->exists('agent-ship_address')), + + 'no_company' => scalar($conf->exists('signup-no_company')), + 'require_phone' => scalar($conf->exists('cust_main-require_phone')), + 'recommend_daytime' => scalar($conf->exists('signup-recommend_daytime')), + 'recommend_email' => scalar($conf->exists('signup-recommend_email')), + }; $cache->set('signup_info_cache', $signup_info_cache); @@ -251,6 +285,32 @@ sub signup_info { if ( $agentnum ) { + warn "$me setting agent-specific payment flag\n" if $DEBUG > 1; + my $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); + warn "$me has agent $agent\n" if $DEBUG > 1; + if ( $agent ) { #else complain loudly? + $signup_info->{'hide_payment_fields'} = []; + foreach my $payby (@{$signup_info->{payby}}) { + warn "$me checking $payby payment fields\n" if $DEBUG > 1; + my $hide = 0; + if ( FS::payby->realtime($payby) ) { + my $payment_gateway = + $agent->payment_gateway( 'method' => FS::payby->payby2bop($payby), + 'nofatal' => 1, + ); + if ( $payment_gateway + && $payment_gateway->gateway_namespace + eq 'Business::OnlineThirdPartyPayment' + ) { + warn "$me hiding $payby payment fields\n" if $DEBUG > 1; + $hide = 1; + } + } + push @{$signup_info->{'hide_payment_fields'}}, $hide; + } + } + warn "$me done setting agent-specific payment flag\n" if $DEBUG > 1; + warn "$me setting agent-specific package list\n" if $DEBUG > 1; $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum} unless @{ $signup_info->{'part_pkg'} }; @@ -270,6 +330,47 @@ sub signup_info { ]; warn "$me done setting agent-specific adv. source list\n" if $DEBUG > 1; + $signup_info->{'agent_name'} = $agent->agent; + + $signup_info->{'company_name'} = $conf->config('company_name', $agentnum); + + if ( $signup_info->{'agent_ship_address'} && $agent->agent_custnum ) { + my $cust_main = $agent->agent_cust_main; + my $prefix = length($cust_main->ship_last) ? 'ship_' : ''; + $signup_info->{"ship_$_"} = $cust_main->get("$prefix$_") + foreach qw( address1 city county state zip country ); + } + + #some of the above could probably be cached, too + + my $signup_info_cache_agent = $cache->get("signup_info_cache_agent$agentnum"); + + if ( $signup_info_cache_agent ) { + + warn "$me loading cached signup info for agentnum $agentnum\n" + if $DEBUG > 1; + + } else { + + warn "$me populating signup info cache for agentnum $agentnum\n" + if $DEBUG > 1; + + $signup_info_cache_agent = { + #( map { $_ => scalar( $conf->config($_, $agentnum) ) } + # qw( company_name ) ), + ( map { $_ => scalar( $conf->config("selfservice-$_", $agentnum ) ) } + qw( body_bgcolor box_bgcolor) ), + ( map { $_ => join("\n", $conf->config("selfservice-$_", $agentnum ) ) } + qw( head body_header body_footer ) ), + }; + + $cache->set("signup_info_cache_agent$agentnum", $signup_info_cache_agent); + + } + + $signup_info->{$_} = $signup_info_cache_agent->{$_} + foreach keys %$signup_info_cache_agent; + } # else { # delete $signup_info->{'part_pkg'}; @@ -381,10 +482,38 @@ sub new_customer { } ); + my $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); + if ( $conf->exists('agent_ship_address') && $agent->agent_custnum ) { + my $agent_cust_main = $agent->agent_cust_main; + my $prefix = length($agent_cust_main->ship_last) ? 'ship_' : ''; + $cust_main->set("ship_$_", $agent_cust_main->get("$prefix$_") ) + foreach qw( address1 city county state zip country ); + + $cust_main->set("ship_$_", $cust_main->get($_)) + foreach qw( last first ); + + } + + return { 'error' => "Illegal payment type" } unless grep { $_ eq $packet->{'payby'} } $conf->config('signup_server-payby'); + if (FS::payby->realtime($packet->{payby})) { + my $payby = $packet->{payby}; + + my $agent = qsearchs('agent', { 'agentnum' => $agentnum }); + return { 'error' => "Unknown reseller" } + unless $agent; + + my $gw = $agent->payment_gateway( 'method' => FS::payby->payby2bop($payby), + 'nofatal' => 1, + ); + + $cust_main->payby('BILL') # MCRD better? + if $gw && $gw->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; + } + $cust_main->payinfo($cust_main->daytime) if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo; @@ -418,14 +547,14 @@ sub new_customer { #return { 'error' => $error } if $error; #should be all auto-magic and shit - my $svc; + my @svc = (); if ( $svc_x eq 'svc_acct' ) { - my $svc = new FS::svc_acct ( { + my $svc = new FS::svc_acct { 'svcpart' => $svcpart, map { $_ => $packet->{$_} } qw( username _password sec_phrase popnum ), - } ); + }; my @acct_snarf; my $snarfnum = 1; @@ -442,21 +571,48 @@ sub new_customer { } $svc->child_objects( \@acct_snarf ); + push @svc, $svc; + } elsif ( $svc_x eq 'svc_phone' ) { my $svc = new FS::svc_phone ( { 'svcpart' => $svcpart, map { $_ => $packet->{$_} } - qw( countrycode phonenum pin ), + qw( countrycode phonenum sip_password pin ), } ); + push @svc, $svc; + } else { die "unknown signup service $svc_x"; } - - my $y = $svc->setdefault; # arguably should be in new method + my $y = $svc[0]->setdefault; # arguably should be in new method return { 'error' => $y } if $y && !ref($y); + if ($packet->{'mac_addr'} && $conf->exists('signup_server-mac_addr_svcparts')) + { + + my %mac_addr_svcparts = map { $_ => 1 } + $conf->config('signup_server-mac_addr_svcparts'); + my @pkg_svc = grep { $_->quantity && $mac_addr_svcparts{$_->svcpart} } + $cust_pkg->part_pkg->pkg_svc; + + return { 'error' => 'No service defined to assign mac address' } + unless @pkg_svc; + + my $svc = new FS::svc_acct { + 'svcpart' => $pkg_svc[0]->svcpart, #multiple matches? alas.. + 'username' => $packet->{'mac_addr'}, + '_password' => '', #blank as requested (set passwordmin to 0) + }; + + my $y = $svc->setdefault; # arguably should be in new method + return { 'error' => $y } if $y && !ref($y); + + push @svc, $svc; + + } + #$error = $svc->check; #return { 'error' => $error } if $error; @@ -470,7 +626,7 @@ sub new_customer { use Tie::RefHash; tie my %hash, 'Tie::RefHash'; - %hash = ( $cust_pkg => [ $svc ] ); + %hash = ( $cust_pkg => \@svc ); #msgcat $error = $cust_main->insert( \%hash, @@ -496,10 +652,22 @@ sub new_customer { # " new customer: $bill_error" # if $bill_error; - $bill_error = $cust_main->collect('realtime' => 1); + $bill_error = $cust_main->realtime_collect( + method => FS::payby->payby2bop( $packet->{payby} ), + depend_jobnum => $placeholder->jobnum, + ); #warn "[fs_signup_server] error collecting from new customer: $bill_error" # if $bill_error; + if ($bill_error && ref($bill_error) eq 'HASH') { + return { 'error' => '_collect', + ( map { $_ => $bill_error->{$_} } + qw(popup_url reference collectitems) + ), + amount => $cust_main->balance, + }; + } + if ( $cust_main->balance > 0 ) { #this makes sense. credit is "un-doing" the invoice @@ -533,7 +701,98 @@ sub new_customer { $error = $placeholder->delete; return { 'error' => $error } if $error; - return { error => '' }; + my %return = ( 'error' => '', + 'signup_service' => $svc_x, + ); + + if ( $svc_x eq 'svc_acct' ) { + $return{$_} = $svc[0]->$_() for qw( username _password ); + } elsif ( $svc_x eq 'svc_phone' ) { + $return{$_} = $svc[0]->$_() for qw( countrycode phonenum sip_password pin ); + } else { + die "unknown signup service $svc_x"; + } + + return \%return; + +} + +sub capture_payment { + my $packet = shift; + + warn "$me capture_payment called on $packet\n" if $DEBUG; + + ### + # identify processor/gateway from called back URL + ### + + my $conf = new FS::Conf; + + my $url = $packet->{url}; + my $payment_gateway = + qsearchs('payment_gateway', { 'gateway_callback_url' => popurl(0, $url) } ); + + unless ($payment_gateway) { + + my ( $processor, $login, $password, $action, @bop_options ) = + $conf->config('business-onlinepayment'); + $action ||= 'normal authorization'; + pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; + die "No real-time processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n" + unless $processor; + + $payment_gateway = new FS::payment_gateway( { + gateway_namespace => $conf->config('business-onlinepayment-namespace'), + gateway_module => $processor, + gateway_username => $login, + gateway_password => $password, + gateway_action => $action, + options => [ ( @bop_options ) ], + }); + + } + + die "No real-time third party processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n*" + unless $payment_gateway->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; + + ### + # locate pending transaction + ### + + eval "use Business::OnlineThirdPartyPayment"; + die $@ if $@; + + my $transaction = + new Business::OnlineThirdPartyPayment( $payment_gateway->gateway_module, + @{ [ $payment_gateway->options ] }, + ); + + my $paypendingnum = $transaction->reference($packet->{data}); + + my $cust_pay_pending = + qsearchs('cust_pay_pending', { paypendingnum => $paypendingnum } ); + + unless ($cust_pay_pending) { + my $bill_error = "No payment is being processed with id $paypendingnum". + "; Transaction aborted."; + return { error => '_decline', bill_error => $bill_error }; + } + + if ($cust_pay_pending->status ne 'pending') { + my $bill_error = "Payment with id $paypendingnum is not pending, but ". + $cust_pay_pending->status. "; Transaction aborted."; + return { error => '_decline', bill_error => $bill_error }; + } + + my $cust_main = $cust_pay_pending->cust_main; + my $bill_error = + $cust_main->realtime_botpp_capture( $cust_pay_pending, %{$packet->{data}} ); + + return { 'error' => ( $bill_error->{bill_error} ? '_decline' : '' ), + %$bill_error, + }; }