Business-OCV
view release on metacpan or search on metacpan
# VPPs, which in turn requires both a multiple-VPP license from Ingenico and
# multiple merchant IDs and/or terminal IDs from the bank). The client (us)
# simply specifies which account to use and the server allocates the first
# available VPP allocated to that account. It returns the MerchantID and
# TerminalID as part of the RESPONSE message, if the client is interested.
#
# The account number 0 is the 'Default' account and cannot be removed.
# The Default account is for the OCV Server's internal use and must not be
# used by clients. Note that the Default account must have a VPP assigned to
# it (which is why you get 6 accounts when you purchase a 5 account license).
# Further, when processing concurrent transactions, if an account is busy
# you'll get a SERVER BUSY response so it pays to allocate as many VPPs to
# an account as possible (and make sure to retry BUSY responses).
#
# OCV DEVELOPMENT SERVER BUGS
#
# The OCV 'Development Server' supplied by Ingenico for testing and
# development purposes has a few bugs which mean it's not an entirely
# reliable means of testing your code. As of v.1.15, it:
# - often locks up and/or crashes with dud messages
# - does not respond well to polled requests. It 'locks' the account after
minamount => 100, # minimum accepted amount (cents)
maxamount => 100000, # maximum accepted amount (cents)
# list of strings to censor from the debug log
# - generally intended to filter 'dynamic' data (i.e. card numbers),
# but can be initialised with a static list of strings
# - card numbers are added with each transaction in _transaction()
debugfilter => [],
# parameters for dealing with SERVER BUSY
busywait => 6, # average time between attempts t = (T/2,3T/2)
busyattempts => 15, # maximum number of attempts
};
# merge arguments
while (my ($k, $v) = each %{$args})
{
$self->{$k} = $v;
}
bless ($self, $class);
}
return $m;
}
############################################
# The following are wrappers around _transaction, one for each "transaction"
# type. Note that due to the way the arguments are parsed, arguments listed
# before the @_ can be overridden by the caller (@_); arguments listed after
# @_ can't be overridden by the caller.
# - the 'nb' subroutines are 'non busy' (or 'non blocking', take your pick),
# that is they'll simply return when SERVER BUSY responses are encountered
# The non-'nb' subs will attempt to retry BUSY responses, up to a point.
# - all transactions need a unique Transaction Reference ID, except for status
# - note that new transaction references should be generated for each attempt,
# successful or not, busy or not.
sub nbpurchase
{
my $self = shift;
my $n = ref($self->{'txnref'}) eq 'CODE' ? &{$self->{'txnref'}} :
$self->{'txnref'}++;
$self->_transaction(TT_TRANS_PURCHASE, TxnRef => $n, @_, AuthNum => '');
}
sub nbrefund
# _transaction will default to the last one.
{
shift->_transaction(TT_TRANS_STATUS,
CardData => '', CardExpiry => '', Amount => '', AuthNum => '',
@_,
PolledMode => POLL_BLOCK);
}
# the following set of subroutines will transparently retry the transaction
# in the face of SERVER BUSY responses (up to a limit)
sub _busy
{
my ($s, $self, @a) = @_;
my $m;
my $n = $self->{'busyattempts'}; # maximum no. of attempts
$m = $s->($self, @a);
while ($m and $m->ResponseCode eq TRANS_BUSY and $n-- > 0)
{
select(undef, undef, undef, $self->{'busywait'} * (0.5 + rand));
$m = $s->($self, @a);
}
return $m;
}
sub purchase { _busy(\&nbpurchase, @_) }
sub refund { _busy(\&nbrefund, @_) }
sub preauth { _busy(\&nbpreauth, @_) }
sub completion { _busy(\&nbcompletion, @_) }
sub status { _busy(\&nbstatus, @_) }
############################################
# now the 'miscellaneous' requests
sub statistics
# Server statistics
# - sends a Statistics request, receives one of two response
# Arguments:
# Reset - set to 1 to reset statistics.
utilities/totals view on Meta::CPAN
warn "REQUEST found: " . (defined $txn{$txnref} ? 'yes' : 'no') . "\n"
if $DEBUG > 2;
# RESPONSE for completed transaction (e.g. from superfluous STATUS)
next unless defined $txn{$txnref};
# ok, extract the PURCHASE data (the amount)
my ($amt, $a) = @{$txn{$txnref}};
# if the response is 'final', cross it off
# - server may have been busy, one or more RESPONSEs should be
# forthcoming containing the final txn status
$txn{$txnref} = undef unless $m->Retry;
# extract the most-used fields once
# - excuse the abbreviated variable names, I'm a lazy typist :-)
my ($r, $d, $c) = ($m->Result, $m->SettleDate, $m->CardBin);
warn "SettleDate = $d\n" if $DEBUG == 2;
warn "SettleDate = $d, Result = $r, AccountNum = $a\n" if $DEBUG > 2;
( run in 0.669 second using v1.01-cache-2.11-cpan-87723dcf8b7 )