X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FClientAPI%2FSignup.pm;h=a178bec9c119df8b7364c89c4193348bc76f1e64;hp=50b0b5df04a8900d30baf85ff1b69f3dfccba25b;hb=f32ac83068c6211f829f1688a1a9cdec71bc6ec7;hpb=8cec20dd7f69a3fb7b6a5e6a853747833e8a7784 diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index 50b0b5df0..a178bec9c 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -2,8 +2,10 @@ package FS::ClientAPI::Signup; use strict; use vars qw( $DEBUG $me ); +use subs qw( _myaccount_cache ); use Data::Dumper; use Tie::RefHash; +use Digest::SHA qw(sha512_hex); use FS::Conf; use FS::Record qw(qsearch qsearchs dbdef); use FS::CGI qw(popurl); @@ -22,8 +24,11 @@ use FS::acct_snarf; use FS::queue; use FS::reg_code; use FS::payby; +use FS::banned_pay; +use FS::part_tag; +use FS::cust_payby; -$DEBUG = 0; +$DEBUG = 1; $me = '[FS::ClientAPI::Signup]'; sub clear_cache { @@ -97,7 +102,7 @@ sub signup_info { my @signup_bools = qw( no_company recommend_daytime recommend_email ); - my @signup_server_scalars = qw( default_pkgpart default_svcpart ); + my @signup_server_scalars = qw( default_pkgpart default_svcpart default_domsvc ); my @selfservice_textareas = qw( head body_header body_footer ); @@ -171,10 +176,12 @@ sub signup_info { 'nomadix' => $conf->exists('signup_server-nomadix'), 'payby' => [ $conf->config('signup_server-payby') ], 'card_types' => card_types(), - 'paytypes' => [ @FS::cust_main::paytypes ], + 'paytypes' => [ FS::cust_payby->paytypes ], 'cvv_enabled' => 1, + 'require_cvv' => $conf->exists('signup-require_cvv'), 'stateid_enabled' => $conf->exists('show_stateid'), 'paystate_enabled' => $conf->exists('show_bankstate'), + 'exempt_groups' => [ grep /\S/, $conf->config('tax-cust_exempt-groups') ], 'ship_enabled' => 1, 'msgcat' => $msgcat, 'label' => $label, @@ -184,8 +191,6 @@ sub signup_info { 'signup_service' => $svc_x, 'company_name' => scalar($conf->config('company_name')), #per-agent? - 'agent_ship_address' => scalar($conf->exists('agent-ship_address')), - 'require_phone' => scalar($conf->exists('cust_main-require_phone')), 'logo' => scalar($conf->config_binary('logo.png')), 'prepaid_template_custnum' => $conf->exists('signup_server-prepaid-template-custnum'), }; @@ -374,13 +379,6 @@ sub signup_info { $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"); @@ -402,8 +400,23 @@ sub signup_info { qw( body_bgcolor box_bgcolor menu_bgcolor ) ), ( map { $_ => join("\n", $conf->config("selfservice-$_", $agentnum ) ) } qw( head body_header body_footer ) ), + ( map { $_ => join("\n", $conf->config("signup_server-$_", $agentnum ) ) } + qw( terms_of_service ) ), + + ( map { $_ => scalar($conf->exists($_, $agentnum)) } + qw(cust_main-require_phone agent-ship_address) ), }; + if ( $signup_info_cache_agent->{'agent-ship_address'} + && $agent->agent_cust_main ) { + + my $cust_main = $agent->agent_cust_main; + my $location = $cust_main->ship_location; + $signup_info_cache_agent->{"ship_$_"} = $location->get($_) + foreach qw( address1 city county state zip country ); + + } + $cache->set("signup_info_cache_agent$agentnum", $signup_info_cache_agent); } @@ -502,8 +515,46 @@ sub new_customer { || $conf->config('signup_server-default_agentnum'); } + my ($bill_hash, $ship_hash); + foreach my $f (FS::cust_main->location_fields) { + # avoid having to change this in front-end code + $bill_hash->{$f} = $packet->{"bill_$f"} || $packet->{$f}; + $ship_hash->{$f} = $packet->{"ship_$f"}; + } + #shares some stuff with htdocs/edit/process/cust_main.cgi... take any # common that are still here and library them. + + my %cust_main = ( + 'agentnum' => $agentnum, + 'refnum' => $packet->{refnum} + || $conf->config('signup_server-default_refnum'), + 'tagnum' => [ FS::part_tag->default_tags ], + + ( map { $_ => $packet->{$_} } qw( + salesnum + ss stateid stateid_state + locale + referral_custnum comments + ) + ), + + ); + + my %insert_options = (); + if ( $packet->{payby} =~ /^(CARD|DCRD|CHEK|DCHK)$/ ) { + $insert_options{cust_payby} = [ + new FS::cust_payby { + map { $_ => $packet->{$_} } qw( + payby + payinfo paycvv paydate payname paystate paytype + paystart_month paystart_year payissue + payip + ), + } + ]; + } + my $template_custnum = $conf->config('signup_server-prepaid-template-custnum'); my $cust_main; if ( $template_custnum && $packet->{prepaid_shortform} ) { @@ -511,82 +562,62 @@ sub new_customer { my $template_cust = qsearchs('cust_main', { 'custnum' => $template_custnum } ); return { 'error' => 'Configuration error' } unless $template_cust; $cust_main = new FS::cust_main ( { - 'agentnum' => $agentnum, - 'refnum' => $packet->{refnum} - || $conf->config('signup_server-default_refnum'), - - ( map { $_ => $template_cust->$_ } qw( - last first company address1 address2 - city county state zip country - daytime night fax - - ship_last ship_first ship_company ship_address1 ship_address2 - ship_city ship_county ship_state ship_zip ship_country - ship_daytime ship_night ship_fax - ) - ), - - ( map { $_ => $packet->{$_} } qw( - ss stateid stateid_state - - payby - payinfo paycvv paydate payname paystate paytype - paystart_month paystart_year payissue - payip - - referral_custnum comments - ) + %cust_main, + map { $_ => $template_cust->$_ } qw( + last first company daytime night fax mobile ), - } ); + $bill_hash = { $template_cust->bill_location->location_hash }; + $ship_hash = { $template_cust->ship_location->location_hash }; + } else { $cust_main = new FS::cust_main ( { - #'custnum' => '', - 'agentnum' => $agentnum, - 'refnum' => $packet->{refnum} - || $conf->config('signup_server-default_refnum'), - + %cust_main, map { $_ => $packet->{$_} } qw( - - last first ss company address1 address2 - city county state zip country - daytime night fax stateid stateid_state - - ship_last ship_first ship_ss ship_company ship_address1 ship_address2 - ship_city ship_county ship_state ship_zip ship_country - ship_daytime ship_night ship_fax - - payby - payinfo paycvv paydate payname paystate paytype - paystart_month paystart_year payissue - payip - - referral_custnum comments - ) - + last first company daytime night fax mobile + override_ban_warn + ), } ); } + my $bill_location = FS::cust_location->new($bill_hash); + my $ship_location; my $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); - if ( $conf->exists('agent_ship_address') && $agent->agent_custnum ) { + if ( $conf->exists('agent-ship_address', $agentnum) + && $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 ); + $ship_location = FS::cust_location->new({ + $agent_cust_main->ship_location->location_hash + }); } + # we don't have an equivalent of the "same" checkbox in selfservice + # so is there a ship address, and if so, is it different from the billing + # address? + elsif ( length($ship_hash->{address1}) > 0 and + grep { $bill_hash->{$_} ne $ship_hash->{$_} } keys(%$ship_hash) + ) { + + $ship_location = FS::cust_location->new( $ship_hash ); + + } + else { + $ship_location = $bill_location; + } + $cust_main->set('bill_location' => $bill_location); + $cust_main->set('ship_location' => $ship_location); return { 'error' => "Illegal payment type" } unless grep { $_ eq $packet->{'payby'} } $conf->config('signup_server-payby'); - if (FS::payby->realtime($packet->{payby})) { + if (FS::payby->realtime($packet->{payby}) + and not $conf->exists('signup_server-third_party_as_card')) { my $payby = $packet->{payby}; my $agent = qsearchs('agent', { 'agentnum' => $agentnum }); @@ -605,10 +636,15 @@ sub new_customer { ); } - $cust_main->payby('BILL') # MCRD better? + $cust_main->payby('BILL') # MCRD better? no, that's for something else if $gw && $gw->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; } + return { 'error' => "CVV2 is required" } + if $cust_main->payby =~ /^(CARD|DCRD)$/ + && ! $cust_main->paycvv + && $conf->exists('signup-require_cvv'); + $cust_main->payinfo($cust_main->daytime) if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo; @@ -616,6 +652,12 @@ sub new_customer { ? split( /\s*\,\s*/, $packet->{'invoicing_list'} ) : (); + my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); + my @tax_exempt = grep { $packet->{"tax_$_"} eq 'Y' } @exempt_groups; + $insert_options{'tax_exemption'} = { + map { $_ => $packet->{"tax_$_".'_num'} } @tax_exempt + }; + $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/; my $pkgpart = $1; return { 'error' => 'Please select a package' } unless $pkgpart; #msgcat @@ -623,7 +665,6 @@ sub new_customer { my $part_pkg = qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } ) or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" }; - my $svcpart = $part_pkg->svcpart($svc_x); my $reg_code = ''; if ( $packet->{'reg_code'} ) { @@ -641,50 +682,58 @@ sub new_customer { #my $error = $cust_pkg->check; #return { 'error' => $error } if $error; - #should be all auto-magic and shit my @svc = (); - if ( $svc_x eq 'svc_acct' ) { + unless ( $svc_x eq 'none' ) { - my $svc = new FS::svc_acct { - 'svcpart' => $svcpart, - map { $_ => $packet->{$_} } - qw( username _password sec_phrase popnum ), - }; + my $svcpart = $part_pkg->svcpart($svc_x); + #should be all auto-magic and shit + if ( $svc_x eq 'svc_acct' ) { - my @acct_snarf; - my $snarfnum = 1; - while ( exists($packet->{"snarf_machine$snarfnum"}) - && length($packet->{"snarf_machine$snarfnum"}) ) { - my $acct_snarf = new FS::acct_snarf ( { - 'machine' => $packet->{"snarf_machine$snarfnum"}, - 'protocol' => $packet->{"snarf_protocol$snarfnum"}, - 'username' => $packet->{"snarf_username$snarfnum"}, - '_password' => $packet->{"snarf_password$snarfnum"}, - } ); - $snarfnum++; - push @acct_snarf, $acct_snarf; - } - $svc->child_objects( \@acct_snarf ); - push @svc, $svc; + my $svc = new FS::svc_acct { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( username _password sec_phrase popnum domsvc ), + }; + + my $error = $svc->is_password_allowed($packet->{_password}); + return { error => $error } if $error; + + my @acct_snarf; + my $snarfnum = 1; + while ( exists($packet->{"snarf_machine$snarfnum"}) + && length($packet->{"snarf_machine$snarfnum"}) ) { + my $acct_snarf = new FS::acct_snarf ( { + 'machine' => $packet->{"snarf_machine$snarfnum"}, + 'protocol' => $packet->{"snarf_protocol$snarfnum"}, + 'username' => $packet->{"snarf_username$snarfnum"}, + '_password' => $packet->{"snarf_password$snarfnum"}, + } ); + $snarfnum++; + push @acct_snarf, $acct_snarf; + } + $svc->child_objects( \@acct_snarf ); + push @svc, $svc; - } elsif ( $svc_x eq 'svc_phone' ) { + } elsif ( $svc_x eq 'svc_phone' ) { - push @svc, new FS::svc_phone ( { - 'svcpart' => $svcpart, - map { $_ => $packet->{$_} } - qw( countrycode phonenum sip_password pin ), - } ); + push @svc, new FS::svc_phone ( { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( countrycode phonenum sip_password pin ), + } ); - } elsif ( $svc_x eq 'svc_pbx' ) { + } elsif ( $svc_x eq 'svc_pbx' ) { - push @svc, new FS::svc_pbx ( { - 'svcpart' => $svcpart, - map { $_ => $packet->{$_} } - qw( id title ), - } ); + push @svc, new FS::svc_pbx ( { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( id title ), + } ); - } else { - die "unknown signup service $svc_x"; + } else { + die "unknown signup service $svc_x"; + } + } if ($packet->{'mac_addr'} && $conf->exists('signup_server-mac_addr_svcparts')) @@ -731,6 +780,7 @@ sub new_customer { \%hash, \@invoicing_list, 'depend_jobnum' => $placeholder->jobnum, + %insert_options, ); if ( $error ) { my $perror = $placeholder->delete; @@ -742,7 +792,11 @@ sub new_customer { #warn "$me Billing customer...\n" if $Debug; - my $bill_error = $cust_main->bill( 'depend_jobnum'=>$placeholder->jobnum ); + my @cust_bill; + my $bill_error = $cust_main->bill( + 'depend_jobnum' => $placeholder->jobnum, + 'return_bill' => \@cust_bill, + ); #warn "$me error billing new customer: $bill_error" # if $bill_error; @@ -751,13 +805,15 @@ sub new_customer { # " new customer: $bill_error" # if $bill_error; - $bill_error = $cust_main->realtime_collect( - method => FS::payby->payby2bop( $packet->{payby} ), - depend_jobnum => $placeholder->jobnum, - selfservice => 1, - ); - #warn "$me error collecting from new customer: $bill_error" - # if $bill_error; + unless ( $packet->{payby} eq 'PREPAY' ) { + $bill_error = $cust_main->realtime_collect( + method => FS::payby->payby2bop( $packet->{payby} ), + depend_jobnum => $placeholder->jobnum, + selfservice => 1, + ); + #warn "$me error collecting from new customer: $bill_error" + # if $bill_error; + } if ($bill_error && ref($bill_error) eq 'HASH') { return { 'error' => '_collect', @@ -775,11 +831,11 @@ sub new_customer { if ( $cust_main->balance > 0 ) { - #this makes sense. credit is "un-doing" the invoice - $cust_main->credit( $cust_main->balance, 'signup server decline', - 'reason_type' => $conf->config('signup_credit_type'), - ); - $cust_main->apply_credits; + #this used to apply a credit, but now we can void invoices... + foreach my $cust_bill (@cust_bill) { + my $voiderror = $cust_bill->void('automatic payment failed'); + warn "Error voiding cust bill after decline: $voiderror" if $voiderror; + } #should check list for errors... #$cust_main->suspend; @@ -806,6 +862,18 @@ sub new_customer { $error = $placeholder->delete; return { 'error' => $error } if $error; + if ( $conf->exists('signup-duplicate_cc-warn_hours') ) { + my $hours = $conf->config('signup-duplicate_cc-warn_hours'); + my $ban = new FS::banned_pay $cust_main->_new_banned_pay_hashref; + $ban->end_date( int( time + $hours*3600 ) ); + $ban->bantype('warn'); + $ban->reason('signup-duplicate_cc-warn_hours'); + $error = $ban->insert; + warn "WARNING: error inserting temporary banned_pay for ". + " signup-duplicate_cc-warn_hours (proceeding anyway): $error" + if $error; + } + my %return = ( 'error' => '', 'signup_service' => $svc_x, 'custnum' => $cust_main->custnum, @@ -833,6 +901,227 @@ sub new_customer { } +#false laziness w/ above +# fresh restart to support "free account" portals with 3.x/4.x-style +# addressless accounts +# and a contact (for self-service login) +sub new_customer_minimal { + my $packet = shift; + + my $conf = new FS::Conf; + my $svc_x = $conf->config('signup_server-service') || 'svc_acct'; + + if ( $svc_x eq 'svc_acct' ) { + + #things that aren't necessary in base class, but are for signup server + #return "Passwords don't match" + # if $hashref->{'_password'} ne $hashref->{'_password2'} + return { 'error' => gettext('empty_password') } + unless length($packet->{'_password'}); + # a bit inefficient for large numbers of pops + return { 'error' => gettext('no_access_number_selected') } + unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} )); + + } + elsif ( $svc_x eq 'svc_pbx' ) { + #possibly some validation will be needed + } + + my $agentnum; + if ( exists $packet->{'session_id'} ) { + my $cache = new FS::ClientAPI_SessionCache( { + 'namespace' => 'FS::ClientAPI::Agent', + } ); + my $session = $cache->get($packet->{'session_id'}); + if ( $session ) { + $agentnum = $session->{'agentnum'}; + } else { + return { 'error' => "Can't resume session" }; #better error message + } + } else { + $agentnum = $packet->{agentnum} + || $conf->config('signup_server-default_agentnum'); + } + + #shares some stuff with htdocs/edit/process/cust_main.cgi... take any + # common that are still here and library them. + + my $cust_main = new FS::cust_main ( { + 'agentnum' => $agentnum, + 'refnum' => $packet->{refnum} + || $conf->config('signup_server-default_refnum'), + 'tagnum' => [ FS::part_tag->default_tags ], + + map { $_ => $packet->{$_} } qw( + salesnum + last first company daytime night fax mobile + ss stateid stateid_state + + locale + ), + + } ); + + my %opt = (); + if ( $packet->{payby} =~ /^(CARD|DCRD|CHEK|DCHK)$/ ) { + $opt{cust_payby} = [ + new FS::cust_payby { + map { $_ => $packet->{$_} } qw( + payby + payinfo paycvv paydate payname paystate paytype + paystart_month paystart_year payissue + payip + ), + } + ]; + } + + if ( grep length($packet->{$_}), FS::cust_main->location_fields ) { + my $bill_hash; + foreach my $f (FS::cust_main->location_fields) { + $bill_hash->{$f} = $packet->{$f}; + } + my $bill_location = FS::cust_location->new($bill_hash); + $cust_main->set('bill_location' => $bill_location); + $cust_main->set('ship_location' => $bill_location); + } + + my @invoicing_list = $packet->{'invoicing_list'} + ? split( /\s*\,\s*/, $packet->{'invoicing_list'} ) + : (); + + use Tie::RefHash; + tie my %hash, 'Tie::RefHash', (); + my @svc = (); + + $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/; + my $pkgpart = $1; + + if ( $pkgpart ) { + + my $part_pkg = + qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } ) + or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" }; + + my $cust_pkg = new FS::cust_pkg ( { + #later#'custnum' => $custnum, + 'pkgpart' => $packet->{'pkgpart'}, + } ); + #my $error = $cust_pkg->check; + #return { 'error' => $error } if $error; + + unless ( $svc_x eq 'none' ) { + + my $svcpart = $part_pkg->svcpart($svc_x); + #should be all auto-magic and shit + if ( $svc_x eq 'svc_acct' ) { + + my $svc = new FS::svc_acct { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( username _password sec_phrase popnum domsvc ), + }; + + push @svc, $svc; + + } elsif ( $svc_x eq 'svc_phone' ) { + + push @svc, new FS::svc_phone ( { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( countrycode phonenum sip_password pin ), + } ); + + } elsif ( $svc_x eq 'svc_pbx' ) { + + push @svc, new FS::svc_pbx ( { + 'svcpart' => $svcpart, + map { $_ => $packet->{$_} } + qw( id title ), + } ); + + } else { + die "unknown signup service $svc_x"; + } + + } + + foreach my $svc ( @svc ) { + my $y = $svc->setdefault; # arguably should be in new method + return { 'error' => $y } if $y && !ref($y); + #$error = $svc->check; + #return { 'error' => $error } if $error; + } + + use Tie::RefHash; + tie my %hash, 'Tie::RefHash'; + $hash{ $cust_pkg } = \@svc; + + } + + if ( $invoicing_list[0] && $packet->{'_password'} ) { + $opt{'contact'} = [ + new FS::contact { 'first' => $cust_main->first, + 'last' => $cust_main->get('last'), + '_password' => $packet->{'_password'}, + 'emailaddress' => $invoicing_list[0], + 'selfservice_access' => 'Y', + } + ]; + } + + my $error = $cust_main->insert( + \%hash, + \@invoicing_list, + %opt, + ); + return { 'error' => $error } if $error; + + my $session = { 'custnum' => $cust_main->custnum }; + + my $session_id; + do { + $session_id = sha512_hex(time(). {}. rand(). $$) + } until ( ! defined _myaccount_cache->get($session_id) ); #just in case + + _myaccount_cache->set( $session_id, $session, '1 hour' ); # 1 hour? + + my %return = ( 'error' => '', + 'signup_service' => $svc_x, + 'custnum' => $cust_main->custnum, + 'session_id' => $session_id, + map { $_ => $cust_main->$_ } qw( first last company ), + ); + + if ( $svc[0] ) { + + $return{'svcnum'} = $svc[0]->svcnum; + + 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); + } elsif ( $svc_x eq 'svc_pbx' ) { + #$return{$_} = $svc[0]->$_() for qw( ) #nothing yet + } else { + return {'error' => "configuration error: unknown signup service $svc_x"}; + #die "unknown signup service $svc_x"; + # return an error that's visible to someone somewhere + } + + } + + return \%return; + +} + +use vars qw( $myaccount_cache ); +sub _myaccount_cache { + $myaccount_cache ||= new FS::ClientAPI_SessionCache( { + 'namespace' => 'FS::ClientAPI::MyAccount', + } ); +} + sub capture_payment { my $packet = shift; @@ -903,22 +1192,34 @@ sub capture_payment { 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 ". + if ($cust_pay_pending->status ne 'thirdparty') { + my $bill_error = "Payment with id $paypendingnum is not thirdparty, 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}}, - apply => 1, - ); + if ( $packet->{cancel} ) { + # the user has chosen not to make this payment + # (probably should be a separate API call, but I don't want to duplicate + # all of the above...which should eventually go away) + my $error = $cust_pay_pending->delete; + # don't show any errors related to this; they're not meaningful + warn "error canceling pending payment $paypendingnum: $error\n" if $error; + return { 'error' => '_cancel', + 'session_id' => $cust_pay_pending->session_id }; + } else { + # create the payment + my $bill_error = + $cust_main->realtime_botpp_capture( $cust_pay_pending, + %{$packet->{data}}, + apply => 1, + ); - return { 'error' => ( $bill_error->{bill_error} ? '_decline' : '' ), - %$bill_error, - }; + return { 'error' => ( $bill_error->{bill_error} ? '_decline' : '' ), + %$bill_error, + }; + } }