From: Ivan Kohler Date: Tue, 2 Jul 2013 18:57:03 +0000 (-0700) Subject: Merge branch 'master' of git.freeside.biz:/home/git/freeside X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=3564f619654c5cbf22fc2acbe7eff0c08308e859;hp=fb4a7232c2d703e0a6b8743521b77ae292bb1df8 Merge branch 'master' of git.freeside.biz:/home/git/freeside --- diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 88266da8e..77a4683e5 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -379,6 +379,8 @@ sub access_info { $conf->exists('ticket_system-selfservice_edit_subject') && $cust_main->edit_subject; + $info->{'timeout'} = $conf->config('selfservice-timeout') || 3600; + return { %$info, 'custnum' => $custnum, 'access_pkgnum' => $session->{'pkgnum'}, @@ -830,7 +832,7 @@ sub payment_info { 'save_unchecked' => $conf->exists('selfservice-save_unchecked'), - 'credit_card_surcharge_percentage' => $conf->config('credit-card-surcharge-percentage'), + 'credit_card_surcharge_percentage' => scalar($conf->config('credit-card-surcharge-percentage')), }; } @@ -1252,6 +1254,50 @@ sub realtime_collect { return { 'error' => '', amount => $amount, %$error }; } +sub start_thirdparty { + my $p = shift; + my $session = _cache->get($p->{'session_id'}) + or return { 'error' => "Can't resume session" }; #better error message + my $custnum = $session->{'custnum'}; + my $cust_main = FS::cust_main->by_key($custnum); + + my $amount = $p->{'amount'} + or return { error => 'no amount' }; + + my $result = $cust_main->create_payment( + 'method' => $p->{'method'}, + 'amount' => $p->{'amount'}, + 'pkgnum' => $session->{'pkgnum'}, + 'session_id' => $p->{'session_id'}, + ); + + if ( ref($result) ) { # hashref or error + return $result; + } else { + return { error => $result }; + } +} + +sub finish_thirdparty { + my $p = shift; + my $session_id = delete $p->{'session_id'}; + my $session = _cache->get($session_id) + or return { 'error' => "Can't resume session" }; + my $custnum = $session->{'custnum'}; + my $cust_main = FS::cust_main->by_key($custnum); + + if ( $p->{_cancel} ) { + # customer backed out of making a payment + return $cust_main->cancel_payment( $session_id ); + } + my $result = $cust_main->execute_payment( $session_id, %$p ); + if ( ref($result) ) { + return $result; + } else { + return { error => $result }; + } +} + sub process_payment_order_pkg { my $p = shift; diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index c4cc015e2..42fe9ec4c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2272,6 +2272,12 @@ and customer address. Include units.', }, { + 'key' => 'selfservice-timeout', + 'section' => 'self-service', + 'description' => 'Timeout for the self-service login cookie, in seconds. Defaults to 1 hour.', + }, + + { 'key' => 'backend-realtime', 'section' => 'billing', 'description' => 'Run billing for backend signups immediately.', @@ -3686,7 +3692,7 @@ and customer address. Include units.', { 'key' => 'batchconfig-eft_canada', 'section' => 'billing', - 'description' => 'Configuration for EFT Canada batching, four lines: 1. SFTP username, 2. SFTP password, 3. Transaction code, 4. Number of days to delay process date.', + 'description' => 'Configuration for EFT Canada batching, four lines: 1. SFTP username, 2. SFTP password, 3. Transaction code, 4. Number of days to delay process date. If you are using separate per-agent batches (batch-spoolagent), you must set this option separately for each agent, as the global setting will be ignored.', 'type' => 'textarea', 'per_agent' => 1, }, diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index c50207708..6df45e2b1 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1576,6 +1576,9 @@ sub tables_hashref { #'cust_balance', @money_type, '', '', 'paynum', 'int', 'NULL', '', '', '', 'jobnum', 'bigint', 'NULL', '', '', '', + 'invnum', 'int', 'NULL', '', '', '', + 'manual', 'char', 'NULL', 1, '', '', + 'discount_term','int', 'NULL', '', '', '', ], 'primary_key' => 'paypendingnum', 'unique' => [ [ 'payunique' ] ], diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm index 109343aa3..57093e329 100644 --- a/FS/FS/agent.pm +++ b/FS/FS/agent.pm @@ -230,7 +230,8 @@ sub ticketing_queue { Returns a payment gateway object (see L) for this agent. -Currently available options are I, I, I, and I. +Currently available options are I, I, I, +I, and I. If I is set, and no gateway is available, then the empty string will be returned instead of throwing a fatal exception. @@ -245,10 +246,34 @@ as well. Presently only 'CC', 'ECHECK', and 'PAYPAL' methods are meaningful. When the I is 'CC' then the card number in I can direct this routine to route to a gateway suited for that type of card. +If I is set, the defined self-service payment gateway will +be returned. + =cut sub payment_gateway { my ( $self, %options ) = @_; + + my $conf = new FS::Conf; + + if ( $options{thirdparty} ) { + # still a kludge, but it gets the job done + # and the 'cardtype' semantics don't really apply to thirdparty + # gateways because we have to choose a gateway without ever + # seeing the card number + my $gatewaynum = + $conf->config('selfservice-payment_gateway', $self->agentnum); + my $gateway = FS::payment_gateway->by_key($gatewaynum) + if $gatewaynum; + + if ( $gateway ) { + return $gateway; + } elsif ( $options{'nofatal'} ) { + return ''; + } else { + die "no third-party gateway configured\n"; + } + } my $taxclass = ''; if ( $options{invnum} ) { @@ -276,8 +301,6 @@ sub payment_gateway { $cardtype = cardtype($options{payinfo}); } elsif ( $options{method} eq 'ECHECK' ) { $cardtype = 'ACH'; - } elsif ( $options{method} eq 'PAYPAL' ) { - $cardtype = 'PayPal'; } else { $cardtype = $options{method} } @@ -298,7 +321,6 @@ sub payment_gateway { taxclass => '', } ); my $payment_gateway; - my $conf = new FS::Conf; if ( $override ) { #use a payment gateway override $payment_gateway = $override->payment_gateway; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 940b22a04..7c7c9e2b5 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -6,6 +6,7 @@ use base qw( FS::cust_main::Packages FS::cust_main::Status FS::cust_main::NationalID FS::cust_main::Billing FS::cust_main::Billing_Realtime FS::cust_main::Billing_Discount + FS::cust_main::Billing_ThirdParty FS::cust_main::Location FS::otaker_Mixin FS::payinfo_Mixin FS::cust_main_Mixin FS::geocode_Mixin FS::Quotable_Mixin diff --git a/FS/FS/cust_main/Billing_ThirdParty.pm b/FS/FS/cust_main/Billing_ThirdParty.pm new file mode 100644 index 000000000..faced8f2b --- /dev/null +++ b/FS/FS/cust_main/Billing_ThirdParty.pm @@ -0,0 +1,266 @@ +package FS::cust_main::Billing_ThirdParty; + +use strict; +use vars qw( $DEBUG $me ); +use FS::Record qw( qsearch qsearchs dbh ); +use FS::cust_pay; +use FS::cust_pay_pending; + +$DEBUG = 0; +$me = '[FS::cust_main::Billing_ThirdParty]'; +# arguably doesn't even belong under cust_main... + +=head1 METHODS + +=over 4 + +=item create_payment OPTIONS + +Create a pending payment for a third-party gateway. OPTIONS must include: +- method: a Business::OnlineThirdPartyPayment method argument. Currently + only supports PAYPAL. +- amount: a decimal amount. Unlike in Billing_Realtime, there is NO default. +- session_id: the customer's self-service session ID. + +and may optionally include: +- invnum: the invoice that this payment will apply to +- pkgnum: the package balance that this payment will apply to. +- description: the transaction description for the gateway. +- payip: the IP address the payment is initiated from + +On failure, returns a simple string error message. On success, returns +a hashref of 'url' => the URL to redirect the user to to complete payment, +and optionally 'post_params' => a hashref of name/value pairs to be POSTed +to that URL. + +=cut + +my @methods = qw(PAYPAL CC); +my %method2payby = ( 'PAYPAL' => 'PPAL', 'CC' => 'MCRD' ); + +sub create_payment { + my $self = shift; + my %opt = @_; + + # avoid duplicating this--we just need description and invnum + my $defaults; + $self->_bop_defaults($defaults); + + my $method = $opt{'method'} or return 'method required'; + my $amount = $opt{'amount'} or return 'amount required'; + return "unknown method '$method'" unless grep {$_ eq $method} @methods; + return "amount must be > 0" unless $amount > 0; + return "session_id required" unless length($opt{'session_id'}); + + my $gateway = $self->agent->payment_gateway( + method => $method, + nofatal => 1, + thirdparty => 1, + ); + return "no third-party gateway enabled for method $method" if !$gateway; + + # create pending record + $self->select_for_update; + my @pending = qsearch('cust_pay_pending', { + 'custnum' => $self->custnum, + 'status' => { op=>'!=', value=>'done' } + }); + + # if there are pending payments in the 'thirdparty' state, + # we can safely remove them + foreach (@pending) { + if ( $_->status eq 'thirdparty' ) { + my $error = $_->delete; + return "Error deleting unfinished payment #". + $_->paypendingnum . ": $error\n" if $error; + } else { + return "A payment is already being processed for this customer."; + } + } + + my $cpp = FS::cust_pay_pending->new({ + 'custnum' => $self->custnum, + 'status' => 'new', + 'gatewaynum' => $gateway->gatewaynum, + 'paid' => sprintf('%.2f',$opt{'amount'}), + 'payby' => $method2payby{ $opt{'method'} }, + 'pkgnum' => $opt{'pkgnum'}, + 'invnum' => $opt{'invnum'} || $defaults->{'invnum'}, + 'session_id' => $opt{'session_id'}, + }); + + my $error = $cpp->insert; + return $error if $error; + + my $transaction = $gateway->processor; + # Not included in this content hash: + # payinfo, paydate, paycvv, any kind of recurring billing indicator, + # paystate, paytype (account type), stateid, ss, payname + # + # Also, unlike bop_realtime, we don't allow the magical %options hash + # to override the customer's information. If they need to enter a + # different address or something for the billing provider, they can do + # that after the redirect. + my %content = ( + 'action' => 'create', + 'description' => $opt{'description'} || $defaults->{'description'}, + 'amount' => $amount, + 'customer_id' => $self->custnum, + 'email' => $self->invoicing_list_emailonly_scalar, + 'customer_ip' => $opt{'payip'}, + 'first_name' => $self->first, + 'last_name' => $self->last, + 'address1' => $self->address1, + 'address2' => $self->address2, + 'city' => $self->city, + 'state' => $self->state, + 'zip' => $self->zip, + 'country' => $self->country, + 'phone' => ($self->daytime || $self->night), + ); + + { + local $@; + eval { $transaction->create(%content) }; + if ( $@ ) { + warn "ERROR: Executing third-party payment:\n$@\n"; + return { error => $@ }; + } + } + + if ($transaction->is_success) { + $cpp->status('thirdparty'); + # for whatever is most identifiable as the "transaction ID" + $cpp->payinfo($transaction->token); + # for anything else the transaction needs to remember + $cpp->statustext($transaction->statustext); + $error = $cpp->replace; + return $error if $error; + + return {url => $transaction->redirect, + post_params => $transaction->post_params}; + + } else { + $cpp->status('done'); + $cpp->statustext($transaction->error_message); + $error = $cpp->replace; + return $error if $error; + + return $transaction->error_message; + } + +} + +=item execute_payment SESSION_ID, PARAMS + +Complete the payment and get the status. Triggered from the return_url +handler; PARAMS are all of the CGI parameters we received in the redirect. +On failure, returns an error message. On success, returns a hashref of +'paynum', 'paid', 'order_number', and 'auth'. + +=cut + +sub execute_payment { + my $self = shift; + my $session_id = shift; + my %params = @_; + + my $cpp = qsearchs('cust_pay_pending', { + 'session_id' => uc($session_id), + 'custnum' => $self->custnum, + 'status' => 'thirdparty', + }) + or return 'no payment in process for this session'; + + my $gateway = FS::payment_gateway->by_key( $cpp->gatewaynum ); + my $transaction = $gateway->processor; + $transaction->token($cpp->payinfo); + $transaction->statustext($cpp->statustext); + + { + local $@; + eval { $transaction->execute(%params) }; + if ( $@ ) { + warn "ERROR: Executing third-party payment:\n$@\n"; + return { error => $@ }; + } + } + + my $error; + + if ( $transaction->is_success ) { + + $error = $cpp->approve( + 'processor' => $gateway->gateway_module, + 'order_number' => $transaction->order_number, + 'auth' => $transaction->authorization, + 'payinfo' => '', + 'apply' => 1, + ); + return $error if $error; + + return { + 'paynum' => $cpp->paynum, + 'paid' => $cpp->paid, + 'order_number' => $transaction->order_number, + 'auth' => $transaction->authorization, + } + + } else { + + my $error = $gateway->gateway_module. " error: ". + $transaction->error_message; + + my $jobnum = $cpp->jobnum; + if ( $jobnum ) { + my $placeholder = FS::queue->by_key($jobnum); + + if ( $placeholder ) { + my $e = $placeholder->depended_delete || $placeholder->delete; + warn "error removing provisioning jobs after declined paypendingnum ". + $cpp->paypendingnum. ": $e\n\n" + if $e; + } else { + warn "error finding job $jobnum for declined paypendingnum ". + $cpp->paypendingnum. "\n\n"; + } + } + + # not needed here: + # the raw HTTP response thing when there's no error message + # decline notices (the customer has already seen the decline message) + + # set the pending status + my $e = $cpp->decline($error); + if ( $e ) { + $e = "WARNING: payment declined but pending payment not resolved - ". + "error updating status for pendingnum :".$cpp->paypendingnum. + ": $e\n\n"; + warn $e; + $error = "$e ($error)"; + } + + return $error; + } + +} + +=item cancel_payment SESSION_ID + +Cancel a pending payment attempt. This just cleans up the cust_pay_pending +record. + +=cut + +sub cancel_payment { + my $self = shift; + my $session_id = shift; + my $cust_pay_pending = qsearchs('cust_pay_pending', { + 'session_id' => uc($session_id), + 'status' => 'thirdparty', + }); + return { 'error' => $cust_pay_pending->delete }; +} + +1; + diff --git a/FS/FS/cust_main/Packages.pm b/FS/FS/cust_main/Packages.pm index 8484df50e..152c496d1 100644 --- a/FS/FS/cust_main/Packages.pm +++ b/FS/FS/cust_main/Packages.pm @@ -183,7 +183,6 @@ sub order_pkg { 'pkglinknum' => $link->pkglinknum, 'custnum' => $self->custnum, 'main_pkgnum' => $cust_pkg->pkgnum, - 'locationnum' => $cust_pkg->locationnum, # try to prevent as many surprises as possible 'pkgbatch' => $cust_pkg->pkgbatch, 'start_date' => $cust_pkg->start_date, @@ -196,7 +195,8 @@ sub order_pkg { 'waive_setup' => $cust_pkg->waive_setup, 'allow_pkgpart' => $opt->{'allow_pkgpart'}, }); - $error = $self->order_pkg('cust_pkg' => $pkg); + $error = $self->order_pkg('cust_pkg' => $pkg, + 'locationnum' => $cust_pkg->locationnum); if ( $error ) { $dbh->rollback if $oldAutoCommit; return "inserting supplemental package: $error"; diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index f6954a4bc..69f4c395a 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -190,6 +190,15 @@ A hash of optional arguments may be passed. Currently "manual" is supported. If true, a payment receipt is sent instead of a statement when 'payment_receipt_email' configuration option is set. +About the "manual" flag: Normally, if the 'payment_receipt' config option +is set, and the customer has an invoice email address, inserting a payment +causes a I to be emailed to the customer. If the payment is +considered "manual" (or if the customer has no invoices), then it will +instead send a I. "manual" should be true whenever a +payment is created directly from the web interface, from a user-initiated +realtime payment, or from a third-party payment via self-service. It should +be I when creating a payment from a billing event or from a batch. + =cut sub insert { diff --git a/FS/FS/cust_pay_pending.pm b/FS/FS/cust_pay_pending.pm index f03ed1f3a..8e29f08b6 100644 --- a/FS/FS/cust_pay_pending.pm +++ b/FS/FS/cust_pay_pending.pm @@ -128,8 +128,24 @@ Additional status information. L id. -=item paynum - +=item paynum +Payment number (L) of the completed payment. + +=item invnum + +Invoice number (L) to try to apply this payment to. + +=item manual + +Flag for whether this is a "manual" payment (i.e. initiated through +self-service or the back-office web interface, rather than from an event +or a payment batch). "Manual" payments will cause the customer to be +sent a payment receipt rather than a statement. + +=item discount_term + +Number of months the customer tried to prepay for. =back @@ -203,6 +219,9 @@ sub check { || $self->ut_hexn('session_id') || $self->ut_foreign_keyn('paynum', 'cust_pay', 'paynum' ) || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') + || $self->ut_foreign_keyn('invnum', 'cust_bill', 'invnum') + || $self->ut_flag('manual') + || $self->ut_numbern('discount_term') || $self->payinfo_check() #payby/payinfo/paymask/paydate ; return $error if $error; @@ -296,6 +315,116 @@ sub insert_cust_pay { } +=item approve OPTIONS + +Sets the status of this pending payment to "done" and creates a completed +payment (L). This should be called when a realtime or +third-party payment has been approved. + +OPTIONS may include any of 'processor', 'payinfo', 'discount_term', 'auth', +and 'order_number' to set those fields on the completed payment, as well as +'apply' to apply payments for this customer after inserting the new payment. + +=cut + +sub approve { + my $self = shift; + my %opt = @_; + + my $dbh = dbh; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + + my $cust_pay = FS::cust_pay->new({ + 'custnum' => $self->custnum, + 'invnum' => $self->invnum, + 'pkgnum' => $self->pkgnum, + 'paid' => $self->paid, + '_date' => '', + 'payby' => $self->payby, + 'payinfo' => $self->payinfo, + 'gatewaynum' => $self->gatewaynum, + }); + foreach my $opt_field (qw(processor payinfo auth order_number)) + { + $cust_pay->set($opt_field, $opt{$opt_field}) if exists $opt{$opt_field}; + } + + my %insert_opt = ( + 'manual' => $self->manual, + 'discount_term' => $self->discount_term, + ); + my $error = $cust_pay->insert( %insert_opt ); + if ( $error ) { + # try it again without invnum or discount + # (both of those can make payments fail to insert, and at this point + # the payment is a done deal and MUST be recorded) + $self->invnum(''); + my $error2 = $cust_pay->insert('manual' => $self->manual); + if ( $error2 ) { + # attempt to void the payment? + # no, we'll just stop digging at this point. + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: payment captured but not recorded - error inserting ". + "payment (". ($opt{processor} || $self->payby) . + ": $error2\n(previously tried insert with invnum#".$self->invnum. + ": $error)\npending payment saved as paypendingnum#". + $self->paypendingnum."\n\n"; + warn $e; + return $e; + } + } + if ( my $jobnum = $self->jobnum ) { + my $placeholder = FS::queue->by_key($jobnum); + my $error; + if (!$placeholder) { + $error = "not found"; + } else { + $error = $placeholder->delete; + } + + if ($error) { + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: payment captured but could not delete job $jobnum ". + "for paypendingnum #" . $self->paypendingnum . ": $error\n\n"; + warn $e; + return $e; + } + } + + if ( $opt{'paynum_ref'} ) { + ${ $opt{'paynum_ref'} } = $cust_pay->paynum; + } + + $self->status('done'); + $self->statustext('captured'); + $self->paynum($cust_pay->paynum); + my $cpp_done_err = $self->replace; + + if ( $cpp_done_err ) { + + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: payment captured but could not update pending status ". + "for paypendingnum ".$self->paypendingnum.": $cpp_done_err \n\n"; + warn $e; + return $e; + + } else { + + # commit at this stage--we don't want to roll back if applying + # payments fails + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + if ( $opt{'apply'} ) { + my $apply_error = $self->apply_payments_and_credits; + if ( $apply_error ) { + warn "WARNING: error applying payment: $apply_error\n\n"; + } + } + } + ''; +} + =item decline [ STATUSTEXT ] Sets the status of this pending payment to "done" (with statustext diff --git a/FS/FS/payment_gateway.pm b/FS/FS/payment_gateway.pm index e94a62cf4..68d841855 100644 --- a/FS/FS/payment_gateway.pm +++ b/FS/FS/payment_gateway.pm @@ -53,11 +53,11 @@ currently supported: =item gateway_callback_url - For ThirdPartyPayment only, set to the URL that the user should be redirected to on a successful payment. This will be sent -as a transaction parameter (named "callback_url"). +as a transaction parameter named "return_url". =item gateway_cancel_url - For ThirdPartyPayment only, set to the URL that -the user should be redirected to if they cancel the transaction. PayPal -requires this; other gateways ignore it. +the user should be redirected to if they cancel the transaction. This will +be sent as a transaction parameter named "cancel_url". =item auto_resolve_status - For BatchPayment only, set to 'approve' to auto-approve unresolved payments after some number of days, 'reject' to @@ -277,10 +277,6 @@ sub batch_processor { eval "use Business::BatchPayment;"; die "couldn't load Business::BatchPayment: $@" if $@; - my $conf = new FS::Conf; - my $test_mode = $conf->exists('business-batchpayment-test_transaction'); - $opt{'test_mode'} = 1 if $test_mode; - my $module = $self->gateway_module; my $processor = eval { Business::BatchPayment->create($module, $self->options, %opt) @@ -289,11 +285,46 @@ sub batch_processor { if $@; die "$module does not support test mode" - if $test_mode and not $processor->does('Business::BatchPayment::TestMode'); + if $opt{'test_mode'} + and not $processor->does('Business::BatchPayment::TestMode'); return $processor; } +=item processor OPTIONS + +Loads the module for the processor and returns an instance of it. + +=cut + +sub processor { + local $@; + my $self = shift; + my %opt = @_; + foreach (qw(action username password)) { + if (length($self->get("gateway_$_"))) { + $opt{$_} = $self->get("gateway_$_"); + } + } + $opt{'return_url'} = $self->gateway_callback_url; + $opt{'cancel_url'} = $self->gateway_cancel_url; + + my $conf = new FS::Conf; + my $test_mode = $conf->exists('business-batchpayment-test_transaction'); + $opt{'test_mode'} = 1 if $test_mode; + + my $namespace = $self->gateway_namespace; + eval "use $namespace"; + die "couldn't load $namespace: $@" if $@; + + if ( $namespace eq 'Business::BatchPayment' ) { + # at some point we can merge these, but there's enough special behavior... + return $self->batch_processor(%opt); + } else { + return $namespace->new( $self->gateway_module, $self->options, %opt ); + } +} + # _upgrade_data # # Used by FS::Upgrade to migrate to a new database. diff --git a/FS/bin/freeside-eftca-download b/FS/bin/freeside-eftca-download index d54a724ab..1b7653cb3 100755 --- a/FS/bin/freeside-eftca-download +++ b/FS/bin/freeside-eftca-download @@ -52,7 +52,7 @@ my $conf = new FS::Conf; my @agents; if ( $conf->exists('batch-spoolagent') ) { - @agents = qsearchs('agent', { 'disabled' => '' }); + @agents = qsearch('agent', { 'disabled' => '' }); } else { @agents = (1); } @@ -62,11 +62,14 @@ foreach my $agent (@agents) { my @batchconf; if ( $conf->exists('batch-spoolagent') ) { @batchconf = $conf->config('batchconfig-eft_canada', $agent->agentnum, 1); - next unless $batchconf[0]; + if ( !length($batchconf[0]) ) { + warn "agent '".$agent->agent."' has no batchconfig-eft_canada setting; skipped.\n"; + next; + } } else { @batchconf = $conf->config('batchconfig-eft_canada'); } - # BIN, terminalID, merchantID, username, password + # user, password, transaction code, delay days my $user = $batchconf[0] or die "no EFT Canada batch username configured\n"; my $pass = $batchconf[1] or die "no EFT Canada batch password configured\n"; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 99cbed8c7..8227e5789 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -110,6 +110,9 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'call_time' => 'PrepaidPhone/call_time', 'call_time_nanpa' => 'PrepaidPhone/call_time_nanpa', 'phonenum_balance' => 'PrepaidPhone/phonenum_balance', + + 'start_thirdparty' => 'MyAccount/start_thirdparty', + 'finish_thirdparty' => 'MyAccount/finish_thirdparty', ); @EXPORT_OK = ( keys(%autoload), diff --git a/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html index 9cdb65e36..9c6022290 100644 --- a/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html +++ b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Payment results') %> <%= if ( $error ) { diff --git a/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html b/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html index 603fc0bd2..1e986e1ea 100644 --- a/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html +++ b/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html @@ -1,4 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;custnum=$custnum;action="; ''; %> +<%= $url = "$selfurl?action="; ''; %> Setup services

Purchase additional package

diff --git a/fs_selfservice/FS-SelfService/cgi/change_bill.html b/fs_selfservice/FS-SelfService/cgi/change_bill.html index 7941971ba..06ea12b9b 100755 --- a/fs_selfservice/FS-SelfService/cgi/change_bill.html +++ b/fs_selfservice/FS-SelfService/cgi/change_bill.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Edit billing address') %> <%= if ( $error ) { @@ -6,7 +5,6 @@ } ''; %>
- diff --git a/fs_selfservice/FS-SelfService/cgi/change_password.html b/fs_selfservice/FS-SelfService/cgi/change_password.html index 68b6fd824..22d897362 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_password.html +++ b/fs_selfservice/FS-SelfService/cgi/change_password.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Change password') %> <%= if ( $error ) { @@ -6,7 +5,6 @@ } ''; %> -
diff --git a/fs_selfservice/FS-SelfService/cgi/change_pay.html b/fs_selfservice/FS-SelfService/cgi/change_pay.html index 9633e8920..6898dc7f8 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_pay.html +++ b/fs_selfservice/FS-SelfService/cgi/change_pay.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Change payment information') %> <%= if ( $error ) { @@ -13,7 +12,7 @@ my $preauto = '
). + my $tail = qq(
). qq(). qq(
). qq($error

!; } ''; %> - diff --git a/fs_selfservice/FS-SelfService/cgi/change_ship.html b/fs_selfservice/FS-SelfService/cgi/change_ship.html index 59f91767a..ecd20dc92 100755 --- a/fs_selfservice/FS-SelfService/cgi/change_ship.html +++ b/fs_selfservice/FS-SelfService/cgi/change_ship.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Edit service address') %> <%= if ( $error ) { @@ -6,7 +5,6 @@ } ''; %> - diff --git a/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html index 37dccaaf2..047f8802c 100644 --- a/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Change package') %> <%= include('change_pkg') %> diff --git a/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html index 192c29fa4..5fcf77fac 100755 --- a/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Purchase additional package') %> <%= include('order_pkg') %> diff --git a/fs_selfservice/FS-SelfService/cgi/delete_svc.html b/fs_selfservice/FS-SelfService/cgi/delete_svc.html index 80a14f85c..e2b26789d 100644 --- a/fs_selfservice/FS-SelfService/cgi/delete_svc.html +++ b/fs_selfservice/FS-SelfService/cgi/delete_svc.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Remove service') %> <%= if ( $error ) { diff --git a/fs_selfservice/FS-SelfService/cgi/finish_thirdparty_payment.html b/fs_selfservice/FS-SelfService/cgi/finish_thirdparty_payment.html new file mode 100644 index 000000000..79c02cc60 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/finish_thirdparty_payment.html @@ -0,0 +1,22 @@ +<%= include('header', 'Payment confirmation') %> + +
+<%= if ( $error ) { + $OUT .= 'Payment processing error
'.$error; +} else { + $OUT .= ' + + + + + + + + + + + +'; +} %> +<%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/invoices.html b/fs_selfservice/FS-SelfService/cgi/invoices.html index d155b9343..752805123 100644 --- a/fs_selfservice/FS-SelfService/cgi/invoices.html +++ b/fs_selfservice/FS-SelfService/cgi/invoices.html @@ -1,4 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= $url = "$selfurl?action="; ''; %> <%= include('header', 'All Invoices') %> <%= diff --git a/fs_selfservice/FS-SelfService/cgi/list_customers.html b/fs_selfservice/FS-SelfService/cgi/list_customers.html index 7fe7fa493..974634729 100644 --- a/fs_selfservice/FS-SelfService/cgi/list_customers.html +++ b/fs_selfservice/FS-SelfService/cgi/list_customers.html @@ -1,6 +1,6 @@ ResellerReseller

-<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= $url = "$selfurl?action="; ''; %>
Your payment details
Payment #' . $paynum . '
Payment amount + ' . sprintf('$%.2f', $paid) . '
Processing #' . $order_number . '
<%= include('agent_menu') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/login.html b/fs_selfservice/FS-SelfService/cgi/login.html index f7473b1d5..68f3ae465 100644 --- a/fs_selfservice/FS-SelfService/cgi/login.html +++ b/fs_selfservice/FS-SelfService/cgi/login.html @@ -10,7 +10,7 @@ <%= $error %> - + @@ -65,7 +65,6 @@ if ( $phone_login ) { OR

-
diff --git a/fs_selfservice/FS-SelfService/cgi/logout.html b/fs_selfservice/FS-SelfService/cgi/logout.html index 5e22ad80c..834ef13f2 100644 --- a/fs_selfservice/FS-SelfService/cgi/logout.html +++ b/fs_selfservice/FS-SelfService/cgi/logout.html @@ -1,5 +1,6 @@ + MyAccount <%= $head %> diff --git a/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html index 5b81b00a4..e33ad574c 100644 --- a/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html @@ -1,8 +1,6 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Make a payment') %> -
Phone number
diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html index defd4a551..915714cc3 100644 --- a/fs_selfservice/FS-SelfService/cgi/make_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html @@ -1,8 +1,6 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Make a payment') %> -
diff --git a/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html index 59ee93b00..9a5678e8f 100755 --- a/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html @@ -1,15 +1,12 @@ -<%= $url = "$selfurl?session=$session_id;action="; - $cgi = new CGI; - ''; %> <%= include('header', 'Make a payment') %> +<%= if ( $error ) { + $OUT .= qq!$error

!; +} ''; %> - - +
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html index a6352e07a..66e2c692e 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html @@ -1,4 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= $url = "$selfurl?action="; ''; %> <%= include('header', 'My Account') %> Hello <%= $name %>!

diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html index cf719e849..7d1a5f793 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html @@ -1,4 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= $url = "$selfurl?action="; ''; %>
Balance due
diff --git a/fs_selfservice/FS-SelfService/cgi/order_pkg.html b/fs_selfservice/FS-SelfService/cgi/order_pkg.html index 79335a0c2..84a10abcb 100644 --- a/fs_selfservice/FS-SelfService/cgi/order_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/order_pkg.html @@ -12,7 +12,6 @@ function enable_order_pkg () { $OUT .= qq!$error

!; } ''; %> - diff --git a/fs_selfservice/FS-SelfService/cgi/payment_results.html b/fs_selfservice/FS-SelfService/cgi/payment_results.html index be727cb7d..04a0611d0 100644 --- a/fs_selfservice/FS-SelfService/cgi/payment_results.html +++ b/fs_selfservice/FS-SelfService/cgi/payment_results.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Payment results') %> <%= if ( $error ) { diff --git a/fs_selfservice/FS-SelfService/cgi/post_thirdparty_payment.html b/fs_selfservice/FS-SelfService/cgi/post_thirdparty_payment.html index 17710b2e5..ed7c2a32b 100644 --- a/fs_selfservice/FS-SelfService/cgi/post_thirdparty_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/post_thirdparty_payment.html @@ -1,42 +1,21 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('header', 'Pay now') %> - - - - - - - -<%= if ( $error ) { - $OUT .= qq!$error

!; -}else{ - $OUT .= <
- Your transaction reference number is $reference

- -EOF - -# - my %itemhash = @collectitems; -# my $query = join(';', -# map { uri_escape($_) . '=' . uri_escape($itemhash{$_}) } -# keys(%itemhash) -# ); - foreach my $input (keys(%itemhash)) { - $OUT .= qq!\n!; - } - $OUT .= qq!! + + + Redirecting to payment processor... + + +

Redirecting to payment processor...

+ +<%= foreach my $name (keys %post_params) { + my $value = encode_entities($post_params{$name}); + $OUT .= ' + '; +} %> + + + -%> - -<%= include('footer') %> + + + diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_bill.html b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html index bf7ad778d..795cc12b0 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_bill.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Information updated successfully') %> Information updated successfully. <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_password.html b/fs_selfservice/FS-SelfService/cgi/process_change_password.html index 4eca91fb6..d16c460c3 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_password.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_password.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', "Password changed" ) %> Password changed for <%= $value %> <%= $label %>. diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pay.html b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html index e399aea17..8fb33b299 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_pay.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Information updated successfully' ) %> Information updated successfully. <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html index bf15b6ea6..126e2a454 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Package change successful') %> <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_ship.html b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html index bf7ad778d..795cc12b0 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_ship.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Information updated successfully') %> Information updated successfully. <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html index 649d92092..b76dafbaa 100755 --- a/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Package order successful') %> Package order successful. diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html index 4a16ec56a..659f110df 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html +++ b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', "$svc recharged successfully") %> <%= $svc %> recharged successfully. diff --git a/fs_selfservice/FS-SelfService/cgi/process_suspend_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_suspend_pkg.html index d5c62f4f1..2a9805f18 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_suspend_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/process_suspend_pkg.html @@ -1,3 +1,2 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Package suspended') %> <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html index d6515e7f4..48f6a85ce 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html +++ b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', "$svc setup successfully") %> <%= $svc %> setup successfully. diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_external.html b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html index c20aae02c..48d70b04e 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_svc_external.html +++ b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', "$svc setup successfully") %> <%= $svc %> setup successfully. diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_phone.html b/fs_selfservice/FS-SelfService/cgi/process_svc_phone.html index d6515e7f4..48f6a85ce 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_svc_phone.html +++ b/fs_selfservice/FS-SelfService/cgi/process_svc_phone.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', "$svc setup successfully") %> <%= $svc %> setup successfully. diff --git a/fs_selfservice/FS-SelfService/cgi/provision.html b/fs_selfservice/FS-SelfService/cgi/provision.html index cd8028a0d..808e4b54d 100644 --- a/fs_selfservice/FS-SelfService/cgi/provision.html +++ b/fs_selfservice/FS-SelfService/cgi/provision.html @@ -1,5 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;action="; - $heading1 = "Setup my services"; +<%= $heading1 = "Setup my services"; $heading1 = "Package list" if $wholesale_view; $provision_list = "provision_list"; $provision_list = "ws_list" if $wholesale_view; diff --git a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html index bae57305e..c63a838df 100644 --- a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html +++ b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html @@ -1,4 +1,3 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Setup account') %> <%= include('svc_acct') %> diff --git a/fs_selfservice/FS-SelfService/cgi/provision_svc_phone.html b/fs_selfservice/FS-SelfService/cgi/provision_svc_phone.html index 9a07e7da1..9ac039d74 100644 --- a/fs_selfservice/FS-SelfService/cgi/provision_svc_phone.html +++ b/fs_selfservice/FS-SelfService/cgi/provision_svc_phone.html @@ -1,5 +1,4 @@ -<%= $url = "$selfurl?session=$session_id;action="; - $heading2 = $lnp ? "Port-In Number" : "Setup phone number"; +<%= $heading2 = $lnp ? "Port-In Number" : "Setup phone number"; ''; %> <%= include('header', $heading2) %> @@ -15,8 +14,7 @@ if($error) { } %> -
- + diff --git a/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html index c716e8242..e47f8003a 100644 --- a/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html +++ b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html @@ -1,8 +1,6 @@ -<%= $url = "$selfurl?session=$session_id;action="; ''; %> <%= include('header', 'Recharge with prepaid card') %> -