summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Burger <burgerc@freeside.biz>2018-10-10 12:53:53 -0400
committerChristopher Burger <burgerc@freeside.biz>2018-10-10 12:53:53 -0400
commit2a82381a976c22f2c0d85645e8b327713ddcbd88 (patch)
tree43fd5de23281639139b6b705490b04595f0bb1ac
parent29445ff3f69c32ba0f836f3c5bbaf946c154b360 (diff)
RT# 39340 - created access to payment only via ip address, fixes security by creating a seperate session
-rw-r--r--FS/FS/ClientAPI/MasonComponent.pm29
-rw-r--r--FS/FS/ClientAPI/PaymentOnly.pm472
-rw-r--r--FS/FS/ClientAPI_XMLRPC.pm8
-rw-r--r--fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm1
-rw-r--r--fs_selfservice/FS-SelfService/cgi/change_pay.html2
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/selfservice.cgi6
-rw-r--r--ng_selfservice/elements/payment_only_menu.php101
-rw-r--r--ng_selfservice/payment_only.php52
-rw-r--r--ng_selfservice/payment_only_error.php6
-rw-r--r--ng_selfservice/payment_only_logout.php35
-rw-r--r--ng_selfservice/payment_only_payment.php118
11 files changed, 824 insertions, 6 deletions
diff --git a/FS/FS/ClientAPI/MasonComponent.pm b/FS/FS/ClientAPI/MasonComponent.pm
index d615c27..e216d91 100644
--- a/FS/FS/ClientAPI/MasonComponent.pm
+++ b/FS/FS/ClientAPI/MasonComponent.pm
@@ -2,7 +2,7 @@ package FS::ClientAPI::MasonComponent;
use strict;
use vars qw( $cache $DEBUG $me );
-use subs qw( _cache );
+use subs qw( _cache _mason_comp );
use FS::Mason qw( mason_interps );
use FS::Conf;
use FS::ClientAPI_SessionCache;
@@ -138,8 +138,27 @@ my( $fs_interp, $rt_interp ) = mason_interps('standalone', 'outbuf'=>\$outbuf);
sub mason_comp {
my $packet = shift;
+ my $me = 'mason_comp';
+ my $namespace = 'FS::ClientAPI::MyAccount';
- warn "$me mason_comp called on $packet\n" if $DEBUG;
+ _mason_comp($packet, $me, $namespace);
+
+}
+
+sub payment_only_mason_comp {
+ my $packet = shift;
+ my $me = 'payment_only_mason_comp';
+ my $namespace = 'FS::ClientAPI::PaymentOnly';
+
+ _mason_comp($packet, $me, $namespace);
+}
+
+sub _mason_comp {
+ my $packet = shift;
+ my $me = shift;
+ my $namespace = shift;
+
+ warn "$me called on $packet\n" if $DEBUG;
my $comp = $packet->{'comp'};
unless ( $allowed_comps{$comp} || $session_comps{$comp} ) {
@@ -150,7 +169,7 @@ sub mason_comp {
if ( $session_comps{$comp} ) {
- my $session = _cache->get($packet->{'session_id'})
+ my $session = _cache($namespace)->get($packet->{'session_id'})
or return ( 'error' => "Can't resume session" ); #better error message
my $custnum = $session->{'custnum'};
@@ -175,8 +194,10 @@ sub mason_comp {
#hmm
sub _cache {
+ my $namespace = shift || 'FS::ClientAPI::MyAccount';
+
$cache ||= new FS::ClientAPI_SessionCache( {
- 'namespace' => 'FS::ClientAPI::MyAccount',
+ 'namespace' => $namespace,
} );
}
diff --git a/FS/FS/ClientAPI/PaymentOnly.pm b/FS/FS/ClientAPI/PaymentOnly.pm
new file mode 100644
index 0000000..e1c59a9
--- /dev/null
+++ b/FS/FS/ClientAPI/PaymentOnly.pm
@@ -0,0 +1,472 @@
+package FS::ClientAPI::PaymentOnly;
+
+use 5.008; #require 5.8+ for Time::Local 1.05+
+use strict;
+use vars qw( $cache $DEBUG $me );
+use subs qw( _cache _provision );
+use FS::ClientAPI_SessionCache;
+
+use IO::Scalar;
+use Data::Dumper;
+use Digest::MD5 qw(md5_hex);
+use Digest::SHA qw(sha512_hex);
+use Date::Format;
+use Time::Duration;
+use Time::Local qw(timelocal_nocheck);
+use Business::CreditCard 0.35;
+use HTML::Entities;
+use Text::CSV_XS;
+use Spreadsheet::WriteExcel;
+use OLE::Storage_Lite;
+use FS::UI::Web::small_custview qw(small_custview); #less doh
+use FS::UI::Web;
+use FS::UI::bytecount qw( display_bytecount );
+use FS::Conf;
+#use FS::UID qw(dbh);
+use FS::Record qw(qsearch qsearchs dbh);
+use FS::Msgcat qw(gettext);
+use FS::Misc qw(card_types money_pretty);
+use FS::Misc::DateTime qw(parse_datetime);
+use FS::TicketSystem;
+use FS::ClientAPI_SessionCache;
+use FS::cust_svc;
+use FS::svc_acct;
+use FS::svc_forward;
+use FS::svc_domain;
+use FS::svc_phone;
+use FS::svc_external;
+use FS::svc_dsl;
+use FS::dsl_device;
+use FS::part_svc;
+use FS::cust_main;
+use FS::cust_bill;
+use FS::legacy_cust_bill;
+use FS::cust_main_county;
+use FS::part_pkg;
+use FS::cust_pkg;
+use FS::payby;
+use FS::acct_rt_transaction;
+use FS::msg_template;
+use FS::contact;
+use FS::cust_contact;
+use FS::cust_location;
+use FS::cust_payby;
+
+$DEBUG = 0;
+$me = '[FS::ClientAPI::PaymentOnly]';
+
+sub _cache {
+ $cache ||= new FS::ClientAPI_SessionCache( {
+ 'namespace' => 'FS::ClientAPI::PaymentOnly',
+ } );
+}
+
+sub payment_only_skin_info {
+ my $p = shift;
+
+ my($context, $session, $custnum) = _custoragent_session_custnum($p);
+ #return { 'error' => $session } if $context eq 'error';
+
+ my $agentnum = '';
+ if ( $context eq 'customer' && $custnum ) {
+
+ my $sth = dbh->prepare('SELECT agentnum FROM cust_main WHERE custnum = ?')
+ or die dbh->errstr;
+
+ $sth->execute($custnum) or die $sth->errstr;
+
+ $agentnum = $sth->fetchrow_arrayref->[0]
+ or die "no agentnum for custnum $custnum";
+
+ #} elsif ( $context eq 'agent' ) {
+ } elsif ( defined($p->{'agentnum'}) and $p->{'agentnum'} =~ /^(\d+)$/ ) {
+ $agentnum = $1;
+ }
+ $p->{'agentnum'} = $agentnum;
+
+ my $conf = new FS::Conf;
+
+ #false laziness w/Signup.pm
+
+ my $skin_info_cache_agent = _cache->get("skin_info_cache_agent$agentnum");
+
+ if ( $skin_info_cache_agent ) {
+
+ warn "$me loading cached skin info for agentnum $agentnum\n"
+ if $DEBUG > 1;
+
+ } else {
+
+ warn "$me populating skin info cache for agentnum $agentnum\n"
+ if $DEBUG > 1;
+
+ $skin_info_cache_agent = {
+ 'agentnum' => $agentnum,
+ ( map { $_ => scalar( $conf->config($_, $agentnum) ) }
+ qw( company_name date_format ) ),
+ ( map { $_ => scalar( $conf->config("selfservice-$_", $agentnum ) ) }
+ qw( body_bgcolor box_bgcolor stripe1_bgcolor stripe2_bgcolor
+ text_color link_color vlink_color hlink_color alink_color
+ font title_color title_align title_size menu_bgcolor menu_fontsize
+ )
+ ),
+ 'menu_disable' => [ $conf->config('selfservice-menu_disable',$agentnum) ],
+ ( map { $_ => $conf->exists("selfservice-$_", $agentnum ) }
+ qw( menu_skipblanks menu_skipheadings menu_nounderline no_logo enable_payment_without_balance )
+ ),
+ ( map { $_ => scalar($conf->config_binary("selfservice-$_", $agentnum)) }
+ qw( title_left_image title_right_image
+ menu_top_image menu_body_image menu_bottom_image
+ )
+ ),
+ 'logo' => scalar($conf->config_binary('logo.png', $agentnum )),
+ ( map { $_ => join("\n", $conf->config("selfservice-$_", $agentnum ) ) }
+ qw( head body_header body_footer company_address ) ),
+ 'money_char' => $conf->config("money_char") || '$',
+ 'menu' => 'payment_only_payment.php Make Payment
+
+ payment_only_logout.php Logout
+ ',
+ };
+
+ _cache->set("skin_info_cache_agent$agentnum", $skin_info_cache_agent);
+
+ }
+
+ #{ %$skin_info_cache_agent };
+ $skin_info_cache_agent;
+
+}
+
+sub ip_login {
+ my $p = shift;
+
+ my $conf = new FS::Conf;
+
+ my $svc_x = '';
+ my $session = {};
+ my $cust_main;
+
+ return { error => 'MAC address empty '.$p->{'mac'} }
+ unless $p->{'mac'};
+
+ my $mac_address = $p->{'mac'};
+ $mac_address =~ s/[\:\,\-\. ]//g;
+ $mac_address =~ tr/[a-z]/[A-Z/;
+
+ my $svc_broadband = qsearchs( 'svc_broadband', { 'mac_addr' => $mac_address } );
+ return { error => 'MAC address not found $mac_address '.$p->{'mac'} }
+ unless $svc_broadband;
+ $svc_x = $svc_broadband;
+
+ if ( $svc_x ) {
+
+ $session->{'svcnum'} = $svc_x->svcnum;
+
+ my $cust_svc = $svc_x->cust_svc;
+ my $cust_pkg = $cust_svc->cust_pkg;
+ if ( $cust_pkg ) {
+ $cust_main = $cust_pkg->cust_main;
+ $session->{'custnum'} = $cust_main->custnum;
+ if ( $conf->exists('pkg-balances') ) {
+ my @cust_pkg = grep { $_->part_pkg->freq !~ /^(0|$)/ }
+ $cust_main->ncancelled_pkgs;
+ $session->{'pkgnum'} = $cust_pkg->pkgnum
+ if scalar(@cust_pkg) > 1;
+ }
+ }
+
+ #my $pkg_svc = $svc_acct->cust_svc->pkg_svc;
+ #return { error => 'Only primary user may log in.' }
+ # if $conf->exists('selfservice_server-primary_only')
+ # && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' );
+ my $part_pkg = $cust_pkg->part_pkg;
+ return { error => 'Only primary user may log in.' }
+ if $conf->exists('selfservice_server-primary_only')
+ && $cust_svc->svcpart != $part_pkg->svcpart([qw( svc_acct svc_phone )]);
+
+ }
+ else {
+ return { error => "No Service Found with Mac Address ".$p->{'mac'} };
+ }
+
+ ## get account information
+ my ($cust_payby_card) = $cust_main->cust_payby('CARD', 'DCRD');
+ if ($cust_payby_card) {
+ $session->{'CARD'} = $cust_payby_card->custpaybynum;
+ }
+ my ($cust_payby_check) = $cust_main->cust_payby('CHEK', 'DCHK');
+ if ($cust_payby_check) {
+ $session->{'CHEK'} = $cust_payby_check->custpaybynum;
+ }
+
+ my $session_id;
+ do {
+ $session_id = sha512_hex(time(). {}. rand(). $$)
+ } until ( ! defined _cache->get($session_id) ); #just in case
+
+ my $timeout = $conf->config('selfservice-session_timeout') || '1 hour';
+ _cache->set( $session_id, $session, $timeout );
+
+ return { 'error' => '',
+ 'session_id' => $session_id,
+ %$session,
+ };
+}
+
+sub ip_logout {
+ my $p = shift;
+ my $skin_info = skin_info($p);
+ if ( $p->{'session_id'} ) {
+ _cache->remove($p->{'session_id'});
+ return { %$skin_info, 'error' => '' };
+ } else {
+ return { %$skin_info, 'error' => "Can't resume session" }; #better error message
+ }
+}
+
+sub get_mac_address {
+ my $p = shift;
+
+## access radius exports acct tables to get mac
+ my @part_export = ();
+ @part_export = (
+ qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ),
+ qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } ),
+ qsearch( 'part_export', { 'exporttype' => 'broadband_sqlradius' } ),
+ );
+
+ my @sessions;
+ foreach my $part_export (@part_export) {
+ push @sessions, ( @{ $part_export->usage_sessions( {
+ 'ip' => $p->{'ip'},
+ 'session_status' => 'open',
+ } ) } );
+ }
+
+ return { 'mac_address' => $sessions[0]->{'callingstationid'}, };
+}
+
+sub payment_only_payment_info {
+ my $p = shift;
+ my $session = _cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session today" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ my $payment_info = {
+ 'balance' => $cust_main->balance,
+ };
+
+ #doubleclick protection
+ my $_date = time;
+ $payment_info->{'payunique'} = "webui-PaymentOnly-$_date-$$-". rand() * 2**32; #new
+ $payment_info->{'paybatch'} = $payment_info->{'payunique'}; #back compat
+
+ if ($session->{'CARD'}) {
+ my $card_payby = qsearchs('cust_payby', { 'custpaybynum' => $session->{'CARD'} });
+ if ($card_payby) {
+ $payment_info->{'CARD'} = $session->{'CARD'};
+ $payment_info->{'card_mask'} = $card_payby->paymask;
+ $payment_info->{'card_type'} = $card_payby->paycardtype;
+ }
+ }
+
+ if ($session->{'CHEK'}) {
+ my $check_payby = qsearchs('cust_payby', { 'custpaybynum' => $session->{'CHEK'} });
+ if ($check_payby) {
+ my ($payaccount, $payaba) = split /\@/, $check_payby->paymask;
+ $payment_info->{'CHEK'} = $session->{'CHEK'};
+ $payment_info->{'check_mask'} = $payaccount;
+ $payment_info->{'check_type'} = $check_payby->paytype;
+ }
+ }
+
+ return $payment_info;
+
+}
+
+sub payment_only_process_payment {
+ my $p = shift;
+
+ my $payment_info = _validate_payment($p);
+ return $payment_info if $payment_info->{'error'};
+
+ FS::ClientAPI::MyAccount::do_process_payment($payment_info);
+
+ #return;
+}
+
+sub _validate_payment {
+ 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 = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ $p->{'amount'} =~ /^\s*(\d+(\.\d{2})?)\s*$/
+ or return { 'error' => gettext('illegal_amount') };
+ my $amount = $1;
+ return { error => 'Amount must be greater than 0' } unless $amount > 0;
+
+ #false laziness w/tr-amount_fee.html, but we don't want selfservice users
+ #changing the hidden form values
+ my $conf = new FS::Conf;
+ my $fee_display = $conf->config('selfservice_process-display') || 'add';
+ my $fee_pkgpart = $conf->config('selfservice_process-pkgpart', $cust_main->agentnum);
+ my $fee_skip_first = $conf->exists('selfservice_process-skip_first');
+ if ( $fee_display eq 'add'
+ and $fee_pkgpart
+ and ! $fee_skip_first || scalar($cust_main->cust_pay)
+ )
+ {
+ my $fee_pkg = qsearchs('part_pkg', { pkgpart=>$fee_pkgpart } );
+ $amount = sprintf('%.2f', $amount + $fee_pkg->option('setup_fee') );
+ }
+
+ #$p->{'payby'} ||= 'CARD';
+ $p->{'payby'} =~ /^([A-Z]{4})$/
+ or return { 'error' => "illegal_payby " . $p->{'payby'} };
+ my $payby = $1;
+
+ ## get info from custpaybynum.
+ my $custpayby = qsearchs('cust_payby', { custpaybynum => $session->{$p->{'payby'}} } )
+ or return { 'error' => 'No payment information found' };
+
+ $p->{'discount_term'} =~ /^\s*(\d*)\s*$/
+ or return { 'error' => gettext('illegal_discount_term'). ': '. $p->{'discount_term'} };
+ my $discount_term = $1;
+
+ $p->{'payunique'} =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or return { 'error' => gettext('illegal_text'). " payunique: ". $p->{'payunique'} };
+ my $payunique = $1;
+
+ $p->{'paybatch'} =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or return { 'error' => gettext('illegal_text'). " paybatch: ". $p->{'paybatch'} };
+ my $paybatch = $1;
+
+ $payunique = $paybatch if ! length($payunique) && length($paybatch);
+ my $payname = $custpayby->payname;
+
+ #false laziness w/process/payment.cgi
+ my $payinfo = $custpayby->payinfo;
+ my $onfile = 1;
+ my $paycvv = '';
+ my $replace_cust_payby;
+
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+
+ my ($payinfo1, $payinfo2) = split /\@/, $payinfo;
+ $payinfo1 =~ /^([\dx]+)$/
+ or return { 'error' => "illegal account number " };
+ $payinfo2 =~ /^([\dx]+)$/
+ or return { 'error' => "illegal ABA/routing number " };
+
+ } elsif ( $payby eq 'CARD' || $payby eq 'DCRD' ) {
+
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,19}|\d{8,9})$/
+ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo
+ $payinfo = $1;
+
+ validate($payinfo)
+ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo
+ return { 'error' => gettext('unknown_card_type') }
+ if !$cust_main->tokenized($payinfo) && cardtype($payinfo) eq "Unknown";
+
+ if ( length($p->{'paycvv'}) && $p->{'paycvv'} !~ /^\s*$/ ) {
+ if ( cardtype($payinfo) eq 'American Express card' ) {
+ $p->{'paycvv'} =~ /^\s*(\d{4})\s*$/
+ or return { 'error' => "CVV2 (CID) for American Express cards is four digits." };
+ $paycvv = $1;
+ } else {
+ $p->{'paycvv'} =~ /^\s*(\d{3})\s*$/
+ or return { 'error' => "CVV2 (CVC2/CID) is three digits." };
+ $paycvv = $1;
+ }
+ } elsif ( $conf->exists('selfservice-onfile_require_cvv') ) {
+ return { 'error' => 'CVV2 is required' };
+ } elsif ( !$onfile && $conf->exists('selfservice-require_cvv') ) {
+ return { 'error' => 'CVV2 is required' };
+ }
+
+ } else {
+ die "unknown payby $payby";
+ }
+
+ $p->{$_} = $cust_main->bill_location->get($_)
+ for qw(address1 address2 city state zip);
+
+ my %payby2fields = (
+ 'CARD' => [ qw( paystart_month paystart_year payissue payip
+ address1 address2 city state zip country ) ],
+ 'CHEK' => [ qw( ss paytype paystate stateid stateid_state payip ) ],
+ );
+
+ my $card_type = '';
+ $card_type = cardtype($payinfo) if $payby eq 'CARD';
+
+ my ($year, $month, $day) = split /-/, $custpayby->{Hash}->{paydate};
+
+ my $return = {
+ 'cust_main' => $cust_main, #XXX or just custnum??
+ 'amount' => sprintf('%.2f', $amount),
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paymask' => $custpayby->paymask,
+ 'card_type' => $card_type,
+ 'paydate' => $custpayby->paydate,
+ 'paydate_pretty' => $month. ' / '. $year,
+ 'month' => $month,
+ 'year' => $year,
+ 'payname' => $custpayby->{HASH}->{payname},
+ 'payunique' => $payunique,
+ 'paybatch' => $paybatch,
+ 'paycvv' => $paycvv,
+ 'payname' => $payname,
+ 'discount_term' => $discount_term,
+ 'pkgnum' => $session->{'pkgnum'},
+ map { $_ => $p->{$_} } ( @{ $payby2fields{$payby} } )
+ };
+
+ return $return;
+
+}
+
+sub _custoragent_session_custnum {
+ my $p = shift;
+
+ my($context, $session, $custnum);
+ if ( $p->{'session_id'} ) {
+
+ $context = 'customer';
+ $session = _cache->get($p->{'session_id'})
+ or return ( 'error' => "Can't resume session" ); #better error message
+ $custnum = $session->{'custnum'};
+
+ } elsif ( $p->{'agent_session_id'} ) {
+
+ $context = 'agent';
+ my $agent_cache = new FS::ClientAPI_SessionCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+ $session = $agent_cache->get($p->{'agent_session_id'})
+ or return ( 'error' => "Can't resume session" ); #better error message
+ $custnum = $p->{'custnum'};
+
+ } else {
+ $context = 'error';
+ return ( 'error' => "Can't resume session" ); #better error message
+ }
+
+ ($context, $session, $custnum);
+
+}
+
+1; \ No newline at end of file
diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm
index dcf34fd..430edfe 100644
--- a/FS/FS/ClientAPI_XMLRPC.pm
+++ b/FS/FS/ClientAPI_XMLRPC.pm
@@ -50,6 +50,7 @@ our %typefix = (
'invoice_pdf' => { 'invoice_pdf' => 'base64', },
'legacy_invoice_pdf' => { 'invoice_pdf' => 'base64', },
'skin_info' => \%typefix_skin_info,
+ 'payment_only_skin_info' => \%typefix_skin_info,
'login_info' => \%typefix_skin_info,
'logout' => \%typefix_skin_info,
'access_info' => \%typefix_skin_info,
@@ -215,6 +216,7 @@ sub ss2clientapi {
'suspend_username' => 'Agent/suspend_username',
'unsuspend_username' => 'Agent/unsuspend_username',
'mason_comp' => 'MasonComponent/mason_comp',
+ 'payment_only_mason_comp' => 'MasonComponent/payment_only_mason_comp',
'call_time' => 'PrepaidPhone/call_time',
'call_time_nanpa' => 'PrepaidPhone/call_time_nanpa',
'phonenum_balance' => 'PrepaidPhone/phonenum_balance',
@@ -227,6 +229,12 @@ sub ss2clientapi {
'quotation_add_pkg' => 'MyAccount/quotation/quotation_add_pkg',
'quotation_remove_pkg' => 'MyAccount/quotation/quotation_remove_pkg',
'quotation_order' => 'MyAccount/quotation/quotation_order',
+ 'ip_login' => 'PaymentOnly/ip_login',
+ 'ip_logout' => 'PaymentOnly/ip_logout',
+ 'get_mac_address' => 'PaymentOnly/get_mac_address',
+ 'payment_only_skin_info' => 'PaymentOnly/payment_only_skin_info',
+ 'payment_only_payment_info' => 'PaymentOnly/payment_only_payment_info',
+ 'payment_only_process_payment' => 'PaymentOnly/payment_only_process_payment',
'freesideinc_service' => 'Freeside/freesideinc_service',
};
diff --git a/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm b/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
index 506dce1..58ce6a8 100644
--- a/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
+++ b/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
@@ -45,6 +45,7 @@ our %typefix = (
'invoice_pdf' => { 'invoice_pdf' => 'base64', },
'legacy_invoice_pdf' => { 'invoice_pdf' => 'base64', },
'skin_info' => \%typefix_skin_info,
+ 'payment_only_skin_info' => \%typefix_skin_info,
'login_info' => \%typefix_skin_info,
'logout' => \%typefix_skin_info,
'access_info' => \%typefix_skin_info,
diff --git a/fs_selfservice/FS-SelfService/cgi/change_pay.html b/fs_selfservice/FS-SelfService/cgi/change_pay.html
index f90f6d9..bd64907 100644
--- a/fs_selfservice/FS-SelfService/cgi/change_pay.html
+++ b/fs_selfservice/FS-SelfService/cgi/change_pay.html
@@ -68,7 +68,7 @@
selected_layer => $payby,
# form_name => 'dummy',
# form_action => 'dummy.cgi',
- layer_callback => sub { my $layer = shift; return '<TABLE BGCOLOR="#cccccc">'.$paybychecked{$layer}.qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$layer">$tail!; },
+ layer_callback => sub { my $layer = shift; use MyLog; use Data::Dumper; MyLog->mylog("my layer $layer\n"); return '<TABLE BGCOLOR="#cccccc">'.$paybychecked{$layer}.qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$layer">$tail!; },
)->html;
%>
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
index 3dc69e1..999b812 100755
--- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -284,7 +284,11 @@ sub change_bill {
};
}
sub change_ship { change_bill(@_); }
-sub change_pay { change_bill(@_); }
+sub change_pay {
+ my @payby = ('CARD', 'CHEK', 'DCHK');
+ use MyLog; use Data::Dumper; MyLog->mylog("my change pay at\n".Dumper(@_));
+ change_bill(@_);
+}
sub change_creditcard_pay { change_bill('CARD'); }
sub change_check_pay { change_bill('CHEK'); }
diff --git a/ng_selfservice/elements/payment_only_menu.php b/ng_selfservice/elements/payment_only_menu.php
new file mode 100644
index 0000000..8fb9331
--- /dev/null
+++ b/ng_selfservice/elements/payment_only_menu.php
@@ -0,0 +1,101 @@
+<?
+
+require_once('session.php');
+
+$skin_info = $freeside->payment_only_skin_info( array(
+ 'session_id' => $_COOKIE['session_id'],
+) );
+
+
+if ( isset($skin_info['error']) && $skin_info['error'] ) {
+ $error = $skin_info['error'];
+ header('Location:payment_only_error.php?error='. urlencode($error));
+ die();
+}
+
+extract($skin_info);
+
+?>
+<style type="text/css">
+#menu_ul ul li {
+ display: inline;
+ width: 100%;
+}
+</style>
+
+<ul id="menu_ul">
+
+<?
+
+ $menu_array = explode("\n", $menu);
+ $submenu = array();
+
+ foreach ($menu_array AS $menu_item) {
+ if ( preg_match('/^\s*$/', $menu_item) ) {
+ print_menu($submenu, $current_menu, $menu_disable);
+ $submenu = array();
+ } else {
+ $submenu[] = $menu_item;
+ }
+ }
+ print_menu($submenu, $current_menu, $menu_disable);
+
+ function print_menu($submenu_array, $current_menu, $menu_disable) {
+ if ( count($submenu_array) == 0 ) { return; }
+
+ $links = array();
+ $labels = array();
+ foreach ($submenu_array AS $submenu_item) {
+ $pieces = preg_split('/\s+/', $submenu_item, 2, PREG_SPLIT_NO_EMPTY);
+ $links[] = $pieces[0];
+ $labels[] = $pieces[1];
+ }
+
+ print_link($links[0], $labels[0], $current_menu, $links);
+
+ if ( count($links) > 1 ) {
+ if ( in_array( $current_menu, $links ) ) {
+ echo '<img src="images/dropdown_arrow_white.gif">';
+ } else {
+ echo '<img src="images/dropdown_arrow_white.gif" style="display:none;">';
+ echo '<img src="images/dropdown_arrow_grey.gif">';
+ }
+ }
+
+ array_shift($links);
+ array_shift($labels);
+
+ echo '</a>';
+
+ if ( count($links) > 0 ) {
+ echo '<ul>';
+ foreach ($links AS $link) {
+ $label = array_shift($labels);
+ if ( in_array($label, $menu_disable) == 0) {
+ print_link($link, $label, $current_menu, array($link) );
+ echo '</a></li>';
+ }
+ }
+ echo '</ul>';
+ }
+
+ echo '</li>';
+
+ }
+
+ function print_link($link, $label, $current_menu, $search_array) {
+ echo '<li><a href="'. $link. '"';
+ if ( in_array( $current_menu, $search_array ) ) {
+ echo ' class="current_menu"';
+ }
+ echo '>'. _($label);
+ }
+
+?>
+
+</ul>
+
+<div style="clear:both;"></div>
+<table cellpadding="0" cellspacing="0" border="0" style="min-width:666px">
+<tr>
+<td class="page"> \ No newline at end of file
diff --git a/ng_selfservice/payment_only.php b/ng_selfservice/payment_only.php
new file mode 100644
index 0000000..d348b9c
--- /dev/null
+++ b/ng_selfservice/payment_only.php
@@ -0,0 +1,52 @@
+<?
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$ip = $_SERVER['REMOTE_ADDR'];
+
+$mac = $freeside->get_mac_address( array('ip' => $ip, ) );
+
+$response = $freeside->ip_login( array(
+ 'mac' => $mac['mac_address'],
+) );
+
+$error = $response['error'];
+
+if ( $error ) {
+
+ $title ='Login'; include('elements/header.php');
+ include('elements/error.php');
+ echo "Sorry "+$error;
+
+ // header('Location:index.php?username='. urlencode($mac).
+ // '&domain='. urlencode($domain).
+ // '&email='. urlencode($email).
+ // '&error='. urlencode($error)
+ // );
+
+}
+else {
+ // sucessful login
+
+ $session_id = $response['session_id'];
+ $mac = $mac['mac_address'];
+
+ error_log("[login] logged into freeside with ip=$ip and mac=$mac, setting cookie");
+
+ setcookie('session_id', $session_id);
+
+ $title ='IP Login';
+
+ if ( $response['custnum'] || $response['svcnum'] ) {
+
+ header("Location:payment_only_payment.php");
+ die();
+
+ }
+
+} //successfull login
+
+?>
+
+<? include('elements/footer.php'); ?> \ No newline at end of file
diff --git a/ng_selfservice/payment_only_error.php b/ng_selfservice/payment_only_error.php
new file mode 100644
index 0000000..2ee9f53
--- /dev/null
+++ b/ng_selfservice/payment_only_error.php
@@ -0,0 +1,6 @@
+<? $error = $_GET['error']; ?>
+<? $title ='Payment Only Error'; include('elements/header.php'); ?>
+There was in issue processing your payment.
+<P>
+<? include('elements/error.php'); ?>
+<? include('elements/footer.php'); ?> \ No newline at end of file
diff --git a/ng_selfservice/payment_only_logout.php b/ng_selfservice/payment_only_logout.php
new file mode 100644
index 0000000..e172680
--- /dev/null
+++ b/ng_selfservice/payment_only_logout.php
@@ -0,0 +1,35 @@
+<?
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$response = $freeside->ip_logout( array(
+ 'session_id' => $_COOKIE['session_id'],
+) );
+
+setcookie('session_id', '', time() - 3600);
+
+$error = $response['error'];
+
+if ( $error ) {
+ error_log("Logout error: $error ");
+}
+
+?>
+
+<!DOCTYPE html>
+<HTML>
+ <HEAD>
+ <TITLE>
+ Logged Out
+ </TITLE>
+ <link href="css/default.css" rel="stylesheet" type="text/css"/>
+ <script type="text/javascript" src="js/jquery.js"></script>
+ <script type="text/javascript" src="js/menu.js"></script>
+ </HEAD>
+ <BODY>
+ <FONT SIZE=5>Logged Out</FONT>
+ <BR><BR>
+ You have been logged out.
+ </BODY>
+</HTML> \ No newline at end of file
diff --git a/ng_selfservice/payment_only_payment.php b/ng_selfservice/payment_only_payment.php
new file mode 100644
index 0000000..baed422
--- /dev/null
+++ b/ng_selfservice/payment_only_payment.php
@@ -0,0 +1,118 @@
+<? $title ='Make A Payment'; include('elements/header.php'); ?>
+<? $current_menu = 'payment_only_payment.php'; include('elements/payment_only_menu.php'); ?>
+
+<?
+
+if ( isset($_POST['amount']) && $_POST['amount'] ) {
+
+ $payment_results = $freeside->payment_only_process_payment(array(
+ 'session_id' => $_COOKIE['session_id'],
+ 'payby' => $_POST['payby'],
+ 'amount' => $_POST['amount'],
+ 'paybatch' => $_POST['paybatch'],
+ //'discount_term' => $discount_term,
+ ));
+
+ if ( $payment_results['error'] ) {
+ $error = $payment_results['error'];
+ } else {
+ $receipt_html = $payment_results['receipt_html'];
+ }
+
+}
+
+#echo print_r($payment_results);
+
+if ( $receipt_html ) {
+?>
+
+ Your payment was processed successfully. Thank you.<BR><BR>
+ <? echo $receipt_html; ?>
+
+<? } else {
+
+ $payment_info = $freeside->payment_only_payment_info( array(
+ 'session_id' => $_COOKIE['session_id'],
+ ) );
+
+ if ( isset($payment_info['error']) && $payment_info['error'] ) {
+ $error = $payment_info['error'];
+ // possible to just keep on this page
+ header('Location:payment_only_error.php?error='. urlencode($error));
+ die();
+ }
+
+ extract($payment_info);
+
+ $tr_amount_fee = $freeside->payment_only_mason_comp(array(
+ 'session_id' => $_COOKIE['session_id'],
+ 'comp' => '/elements/tr-amount_fee.html',
+ 'args' => [ 'amount', $balance ],
+ ));
+ //$tr_amount_fee = $tr_amount_fee->{'error'} || $tr_amount_fee->{'output'};
+ $tr_amount_fee = $tr_amount_fee['output'];
+
+ ?>
+
+ <? include('elements/error.php'); ?>
+
+ <SCRIPT TYPE="text/javascript">
+
+ function payby_changed(what) {
+ var amount = document.getElementById('amount');
+ var amountdue = document.getElementById('amountdue');
+ var surcharge_cell = document.getElementById('ajax_surcharge_cell');
+ var surcharge_percentage = document.getElementById('surcharge_percentage');
+ var surcharge_flatfee = document.getElementById('surcharge_flatfee');
+ if (what.value == "CHEK") {
+ surcharge_cell.style.display = 'none';
+ amount.value = amountdue.value;
+
+ }
+ else if (what.value == "CARD") {
+ surcharge_cell.style.display = 'inline';
+ amount.value = (+amountdue.value + (+amountdue.value * +surcharge_percentage.value) + +surcharge_flatfee.value).toFixed(2);
+ }
+ }
+
+ </SCRIPT>
+
+ <FORM NAME="OneTrueForm" METHOD="POST" ACTION="payment_only_payment.php" onSubmit="document.OneTrueForm.process.disabled=true">
+
+ <TABLE>
+
+ <TR>
+ <TD ALIGN="right"><B>Payment account</B></TD>
+ <TD COLSPAN=7>
+ <SELECT ID="payby" NAME="payby" onChange="payby_changed(this)">
+<? if ($CARD) { ?>
+ <OPTION VALUE="CARD"><? echo $card_type ?> <? echo $card_mask ?></OPTION>
+<? } ?>
+<? if ($CHEK) { ?>
+ <OPTION VALUE="CHEK"><? echo $check_type ?> <? echo $check_mask ?></OPTION>
+<? } ?>
+ </SELECT>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right"><B>Amount&nbsp;Due</B></TD>
+ <TD COLSPAN=7>
+ <TABLE><TR><TD>
+ $<? echo sprintf("%.2f", $balance) ?>
+ <INPUT TYPE=hidden NAME="amountdue" ID="amountdue" VALUE="<? echo sprintf("%.2f", $balance) ?>" >
+ </TD></TR></TABLE>
+ </TD>
+ </TR>
+
+ <? echo $tr_amount_fee; ?>
+
+ </TABLE>
+ <BR>
+ <INPUT TYPE="hidden" NAME="paybatch" VALUE="<? echo $paybatch ?>">
+ <INPUT TYPE="submit" NAME="process" VALUE="Process payment"> <!-- onClick="this.disabled=true"> -->
+ </FORM>
+
+<? } ?>
+<? include('elements/menu_footer.php'); ?>
+<? include('elements/footer.php'); ?> \ No newline at end of file