pos/is4c-nf/plugins/Paycards/ValueLink.php
<?php
/*******************************************************************************
Copyright 2007,2010 Whole Foods Co-op
This file is part of IT CORE.
IT CORE is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
IT CORE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
in the file license.txt along with IT CORE; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*********************************************************************************/
/* Test cards:
*
7777080383164347
7777080383174622
*/
use COREPOS\pos\lib\Database;
use COREPOS\pos\lib\TransRecord;
if (!class_exists("AutoLoader")) include_once(realpath(dirname(__FILE__).'/../../lib/AutoLoader.php'));
if (!class_exists("PaycardLib")) include_once(realpath(dirname(__FILE__)."/lib/PaycardLib.php"));
class ValueLink extends BasicCCModule
{
// BEGIN INTERFACE METHODS
private $pmod;
private $dialogs;
public function __construct()
{
$this->pmod = new PaycardModule();
$this->dialogs = new PaycardDialogs();
$this->pmod->setDialogs($this->dialogs);
$this->conf = new PaycardConf();
}
/* handlesType($type)
* $type is a constant as defined in paycardLib.php.
* If you class can handle the given type, return
* True
*/
public function handlesType($type)
{
if ($type == PaycardLib::PAYCARD_TYPE_VALUELINK) {
return true;
}
return false;
}
/* entered($validate)
* This function is called in paycardEntered()
* [paycardEntered.php]. This function exists
* to move all type-specific handling code out
* of the paycard* files
*/
public function entered($validate,$json)
{
try {
$this->dialogs->enabledCheck();
// error checks based on processing mode
if ($this->conf->get("paycard_mode") == PaycardLib::PAYCARD_MODE_VOID) {
$pan4 = substr($this->getPAN(), -4);
$trans = array($this->conf->get('CashierNo'), $this->conf->get('laneno'), $this->conf->get('transno'));
$result = $this->dialogs->voidableCheck($pan4, $trans);
return $this->paycardVoid($result,-1,-1,$json);
}
// check card data for anything else
if ($validate) {
$this->dialogs->validateCard($this->conf->get('paycard_PAN'), false, false);
}
if ($this->conf->get("paycard_mode") == PaycardLib::PAYCARD_MODE_AUTH) {
$dbc = Database::tDataConnect();
$res = $dbc->query("SELECT SUM(total) AS ttl FROM localtemptrans WHERE department=902");
$row = $dbc->fetchRow($res);
if ($row && abs($row['ttl']) > 0.005) {
throw new Exception(PaycardLib::paycardErrBox("Gift Card Error",
"cannot pay for gift card with a gift card",
"[clear] to cancel"
));
}
}
} catch (Exception $ex) {
$json['output'] = $ex->getMessage();
return $json;
}
// other modes
switch ($this->conf->get("paycard_mode")) {
case PaycardLib::PAYCARD_MODE_AUTH:
$this->conf->set('CacheCardType', 'GIFT');
return PaycardLib::setupAuthJson($json);
case PaycardLib::PAYCARD_MODE_ACTIVATE:
case PaycardLib::PAYCARD_MODE_ADDVALUE:
$this->conf->set("paycard_amount",0);
$this->conf->set("paycard_id",$this->conf->get("LastID")+1); // kind of a hack to anticipate it this way..
$pluginInfo = new Paycards();
$json['main_frame'] = $pluginInfo->pluginUrl().'/gui/paycardboxMsgGift.php';
return $json;
case PaycardLib::PAYCARD_MODE_BALANCE:
$pluginInfo = new Paycards();
$json['main_frame'] = $pluginInfo->pluginUrl().'/gui/paycardboxMsgBalance.php';
return $json;
} // switch mode
// if we're still here, it's an error
$json['output'] = $this->dialogs->invalidMode();
$this->conf->reset();
return $json;
}
/* doSend()
* Process the paycard request and return
* an error value as defined in paycardLib.php.
*
* On success, return PaycardLib::PAYCARD_ERR_OK.
* On failure, return anything else and set any
* error messages to be displayed in
* $this->conf->["boxMsg"].
*/
public function doSend($type)
{
$this->secondTry = false;
switch($type) {
case PaycardLib::PAYCARD_MODE_ACTIVATE:
case PaycardLib::PAYCARD_MODE_ADDVALUE:
case PaycardLib::PAYCARD_MODE_AUTH:
return $this->sendAuth();
case PaycardLib::PAYCARD_MODE_VOID:
return $this->sendVoid();
case PaycardLib::PAYCARD_MODE_BALANCE:
return $this->sendBalance();
default:
return $this->setErrorMsg(0);
}
}
/* cleanup()
* This function is called when doSend() returns
* PaycardLib::PAYCARD_ERR_OK. (see paycardAuthorize.php)
* I use it for tendering, printing
* receipts, etc, but it's really only for code
* cleanliness. You could leave this as is and
* do all the everything inside doSend()
*/
public function cleanup($json)
{
switch ($this->conf->get("paycard_mode")) {
case PaycardLib::PAYCARD_MODE_BALANCE:
$resp = $this->conf->get("paycard_response");
$this->conf->set("boxMsg","<b>Success</b><font size=-1>
<p>Gift card balance: $" . $resp["Balance"] . "
<p>\"rp\" to print
<br>[enter] to continue</font>"
);
break;
case PaycardLib::PAYCARD_MODE_ADDVALUE:
case PaycardLib::PAYCARD_MODE_ACTIVATE:
$ttl = $this->conf->get("paycard_amount");
$dept = $this->conf->get('PaycardDepartmentGift');
$dept = $dept == '' ? 902 : $dept;
$deptObj = new COREPOS\pos\lib\DeptLib($this->conf);
$deptObj->deptkey($ttl*100, $dept . '0');
$resp = $this->conf->get("paycard_response");
$this->conf->set("boxMsg","<b>Success</b><font size=-1>
<p>New card balance: $" . $resp["Balance"] . "
<p>[enter] to continue
<br>\"rp\" to reprint slip</font>"
);
break;
case PaycardLib::PAYCARD_MODE_AUTH:
$amt = "".(-1*($this->conf->get("paycard_amount")));
$recordID = $this->last_paycard_transaction_id;
$charflag = ($recordID != 0) ? 'PT' : '';
$tcode = $this->conf->get('PaycardsTenderCodeGift');
$tcode = $tcode == '' ? 'GD' : $tcode;
TransRecord::addFlaggedTender("Gift Card", $tcode, $amt, $recordID, $charflag);
$resp = $this->conf->get("paycard_response");
$this->conf->set("boxMsg","<b>Approved</b><font size=-1>
<p>Used: $" . $this->conf->get("paycard_amount") . "
<br />New balance: $" . $resp["Balance"] . "
<p>[enter] to continue
<br>\"rp\" to reprint slip
<br>[clear] to cancel and void</font>"
);
break;
case PaycardLib::PAYCARD_MODE_VOID:
$void = new COREPOS\pos\parser\parse\VoidCmd($this->conf);
$void->voidid($this->conf->get("paycard_id"), array());
$resp = $this->conf->get("paycard_response");
$this->conf->set("boxMsg","<b>Voided</b><font size=-1>
<p>New balance: $" . $resp["Balance"] . "
<p>[enter] to continue
<br>\"rp\" to reprint slip</font>"
);
break;
}
return $json;
}
/* paycardVoid($transID)
* Argument is trans_id to be voided
* Again, this is for removing type-specific
* code from paycard*.php files.
*/
public function paycardVoid($transID,$laneNo=-1,$transNo=-1,$json=array())
{
$this->voidTrans = "";
$this->voidRef = "";
$ret = $this->pmod->ccVoid($transID, $laneNo, $transNo, $json);
// save the details
$this->conf->set("paycard_type",PaycardLib::PAYCARD_TYPE_GIFT);
$this->conf->set("paycard_mode",PaycardLib::PAYCARD_MODE_VOID);
return $ret;
}
// END INTERFACE METHODS
private function sendAuth()
{
$this->GATEWAY = 'https://api.payeezy.com/v1/transactions';
$this->GATEWAY = 'https://api.globalgatewaye4.firstdata.com/transaction/v32';
if ($this->conf->get("training") == 1) {
$this->GATEWAY = 'https://api-cert.payeezy.com/v1/transactions';
$this->GATEWAY = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v32';
}
// initialize
$dbTrans = Database::tDataConnect();
if (!$dbTrans) {
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_NOSEND); // internal error, nothing sent (ok to retry)
}
// prepare data for the request
$today = date('Ymd'); // numeric date only, it goes in an 'int' field as part of the primary key
$now = date('Y-m-d H:i:s'); // full timestamp
$cashierNo = $this->conf->get("CashierNo");
$laneNo = $this->conf->get("laneno");
$transNo = $this->conf->get("transno");
$transID = $this->conf->get("paycard_id");
$amount = $this->conf->get("paycard_amount");
$amountText = sprintf('%.2f', $amount);
switch ($this->conf->get("paycard_mode")) {
case PaycardLib::PAYCARD_MODE_AUTH:
$authMethod = $amount < 0 ? 'Reload' : 'Purchase';
break;
case PaycardLib::PAYCARD_MODE_ADDVALUE:
$authMethod = 'Reload';
break;
case PaycardLib::PAYCARD_MODE_ACTIVATE:
$authMethod = 'Reload';
break;
default:
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_NOSEND);
}
$live = 0;
$manual = ($this->conf->get("paycard_manual") ? 1 : 0);
$cardPAN = $this->getPAN();
$identifier = $this->refnum($transID);
/**
Log transaction in newer table
*/
$insQ = sprintf("INSERT INTO PaycardTransactions (
dateID, empNo, registerNo, transNo, transID,
processor, refNum, live, cardType, transType,
amount, PAN, issuer, name, manual, requestDateTime)
VALUES (
%d, %d, %d, %d, %d,
'%s', '%s', %d, '%s', '%s',
%.2f, '%s', '%s', '%s', %d, '%s')",
$today, $cashierNo, $laneNo, $transNo, $transID,
'ValueLink', $identifier, $live, 'Gift', $authMethod,
$amount, $cardPAN,
'Mercury', 'Cardholder', $manual, $now);
$insR = $dbTrans->query($insQ);
if ($insR === false) {
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_NOSEND); // internal error, nothing sent (ok to retry)
}
$this->last_paycard_transaction_id = $dbTrans->insertID();
$msgJson = array(
'amount' => $amountText,
'transaction_type' => $authMethod == 'Purchase' ? '00' : '88',
'cardholder_name' => 'Cardholder',
'cc_number' => $cardPAN,
'credit_card_type' => 'gift',
'gateway_id' => $this->conf->get('ValueLinkGatewayID'),
'password' => $this->conf->get('ValueLinkPassword'),
);
$msgJson = json_encode($msgJson);
$gmtime = gmdate('c');
$hmac = $this->getHMAC($msgJson, $gmtime);
$extraHeaders = array(
CURLOPT_HTTPHEADER => array(
'Content-type: application/json',
'Accept: application/json',
'x-gge4-content-sha1: ' . sha1($msgJson),
'x-gge4-date: ' . $gmtime,
'Authorization: GGE4_API ' . $this->conf->get('ValueLinkHmacID') . ':' . $hmac,
),
);
return $this->curlSend($msgJson, 'POST', false, $extraHeaders);
}
private function sendVoid()
{
$this->GATEWAY = 'https://api.payeezy.com/v1/transactions/' . $authcode;
$this->GATEWAY = 'https://api.globalgatewaye4.firstdata.com/transaction/v32';
if ($this->conf->get("training") == 1) {
$this->GATEWAY = 'https://api-cert.payeezy.com/v1/transactions/'. $authcode;
$this->GATEWAY = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v32';
}
// initialize
$dbTrans = Database::tDataConnect();
if (!$dbTrans) {
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_NOSEND); // database error, nothing sent (ok to retry)
}
// prepare data for the void request
$today = date('Ymd'); // numeric date only, it goes in an 'int' field as part of the primary key
$cashierNo = $this->conf->get("CashierNo");
$laneNo = $this->conf->get("laneno");
$transNo = $this->conf->get("transno");
$transID = $this->conf->get("paycard_id");
$amount = $this->conf->get("paycard_amount");
$amountText = sprintf('%.2f', $amount);
$cardPAN = $this->getPAN();
$identifier = date('mdHis'); // the void itself needs a unique identifier, so just use a timestamp minus the year (10 digits only)
// look up the auth code from the original response
// (card number and amount should already be in session vars)
$sql = "SELECT
xApprovalNumber AS xAuthorizationCode
FROM PaycardTransactions
WHERE dateID='" . $today . "'
AND empNo=" . $cashierNo . "
AND registerNo=" . $laneNo . "
AND transNo=" . $transNo . "
AND transID=" . $transID;
$search = $dbTrans->query($sql);
if (!$search || $dbTrans->numRows($search) == 0) {
return PaycardLib::PAYCARD_ERR_NOSEND; // database error, nothing sent (ok to retry)
}
$log = $dbTrans->fetchRow($search);
$authcode = $log['xAuthorizationCode'];
// look up original transaction type
$sql = "SELECT transType AS mode
FROM PaycardTransactions
WHERE dateID='" . $today . "'
AND empNo=" . $cashierNo . "
AND registerNo=" . $laneNo . "
AND transNo=" . $transNo . "
AND transID=" . $transID;
$search = $dbTrans->query($sql);
if (!$search || $dbTrans->numRows($search) == 0) {
return PaycardLib::PAYCARD_ERR_NOSEND; // database error, nothing sent (ok to retry)
}
$row = $dbTrans->fetchRow($search);
/**
populate a void record in PaycardTransactions
*/
$initQ = "INSERT INTO PaycardTransactions (
dateID, empNo, registerNo, transNo, transID,
previousPaycardTransactionID, processor, refNum,
live, cardType, transType, amount, PAN, issuer,
name, manual, requestDateTime)
SELECT dateID, empNo, registerNo, transNo, transID,
paycardTransactionID, processor, refNum,
live, cardType, 'VOID', amount, PAN, issuer,
name, manual, " . $dbTrans->now() . "
FROM PaycardTransactions
WHERE
dateID=" . $today . "
AND empNo=" . $cashierNo . "
AND registerNo=" . $laneNo . "
AND transNo=" . $transNo . "
AND transID=" . $transID;
$initR = $dbTrans->query($initQ);
if ($initR === false) {
return PaycardLib::PAYCARD_ERR_NOSEND; // database error, nothing sent (ok to retry)
}
$this->last_paycard_transaction_id = $dbTrans->insertID();
$json = array(
'amount' => $amountText,
'transaction_type' => '13',
'cardholder_name' => 'Cardholder',
'cc_number' => $cardPAN,
'credit_card_type' => 'gift',
'authorization_num' => $authcode,
'gateway_id' => $this->conf->get('ValueLinkGatewayID'),
'password' => $this->conf->get('ValueLinkPassword'),
);
$msgJson = json_encode($msgJson);
$gmtime = gmdate('c');
$hmac = $this->getHMAC($msgJson, $gmtime);
$extraHeaders = array(
CURLOPT_HTTPHEADER => array(
'Content-type: application/json',
'Accept: application/json',
'x-gge4-content-sha1: ' . sha1($msgJson),
'x-gge4-date: ' . $gmtime,
'Authorization: GGE4_API ' . $this->conf->get('ValueLinkHmacID') . ':' . $hmac,
),
);
return $this->curlSend($msgJson, 'POST', false, $extraHeaders);
}
private function sendBalance($domain="w1.mercurypay.com")
{
$this->GATEWAY = 'https://api.globalgatewaye4.firstdata.com/transaction/v32';
if ($this->conf->get("training") == 1) {
$this->GATEWAY = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v32';
}
$gwID = $this->conf->get('ValueLinkGatewayID');
$msgJson = array(
'transaction_type' => '86',
'cardholder_name' => 'Cardholder',
'cc_number' => $this->getPAN(),
'credit_card_type' => 'gift',
'gateway_id' => $gwID,
'password' => $this->conf->get('ValueLinkPassword'),
);
$msgJson = json_encode($msgJson);
$gmtime = gmdate('c');
$hmac = $this->getHMAC($msgJson, $gmtime);
$extraHeaders = array(
CURLOPT_HTTPHEADER => array(
'Content-type: application/json',
'Accept: application/json',
'x-gge4-content-sha1: ' . sha1($msgJson),
'x-gge4-date: ' . $gmtime,
'Authorization: GGE4_API ' . $this->conf->get('ValueLinkHmacID') . ':' . $hmac,
),
);
return $this->curlSend($msgJson, 'POST', false, $extraHeaders);
}
public function handleResponse($authResult)
{
switch($this->conf->get("paycard_mode")) {
case PaycardLib::PAYCARD_MODE_AUTH:
case PaycardLib::PAYCARD_MODE_ACTIVATE:
case PaycardLib::PAYCARD_MODE_ADDVALUE:
return $this->handleResponseAuth($authResult);
case PaycardLib::PAYCARD_MODE_VOID:
return $this->handleResponseVoid($authResult);
case PaycardLib::PAYCARD_MODE_BALANCE:
return $this->handleResponseBalance($authResult);
}
}
private function handleResponseAuth($authResult)
{
$json = json_decode($authResult['response'], true);
// initialize
$dbTrans = Database::tDataConnect();
$now = date('Y-m-d H:i:s'); // full timestamp
$validResponse = 1;
$errorMsg = '';
if (isset($json['Error'])) {
foreach ($json['Error']['messages'] as $err) {
$errorMsg .= $err['code'] . ' ';
}
}
$balance = isset($json['current_balance']) ? $json['current_balance'] : 0;
$tranType = $json['transaction_type'];
$status = $json['bank_message'];
$normalized = $this->getNormalized($status);
$resultCode = ($normalized >= 3) ? 0 : $normalized;
$rMsg = $normalized === 3 ? substr($errorMsg, 0, 100) : $status;
$apprNumber = isset($json['authorization_num']) ? $json['authorization_num'] : '';
$finishQ = sprintf("UPDATE PaycardTransactions SET
responseDatetime='%s',
seconds=%f,
commErr=%d,
httpCode=%d,
validResponse=%d,
xResultCode=%d,
xApprovalNumber='%s',
xResponseCode=%d,
xResultMessage='%s',
xTransactionID='%s',
xBalance=%.2f
WHERE paycardTransactionID=%d",
$now,
$authResult['curlTime'],
$authResult['curlErr'],
$authResult['curlHTTP'],
$normalized,
$resultCode,
$apprNumber,
$resultCode,
$rMsg,
$apprNumber,
$balance,
$this->last_paycard_transaction_id
);
$dbTrans->query($finishQ);
// check for communication errors
if ($authResult['curlErr'] != CURLE_OK) {
if ($authResult['curlHTTP'] == '0') {
$this->conf->set("boxMsg","No response from processor<br />The transaction did not go through");
return PaycardLib::PAYCARD_ERR_PROC;
}
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_COMM);
}
// check for data errors (any failure to parse response XML or echo'd field mismatch
if ($validResponse != 1) {
// invalid server response, we don't know if the transaction was processed (use carbon)
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_DATA);
}
// put the parsed response into session so the caller, receipt printer, etc can get the data they need
$this->conf->set("paycard_response",array(
'Balance' => strlen($balance) > 0 ? $balance : 0,
));
/**
Update authorized amount based on response. If
the transaction was a refund ("Return") then the
amount needs to be negative for POS to handle
it correctly.
*/
if ($normalized == 1) {
$realAmt = $json['amount'];
if ($realAmt != $this->conf->get('paycard_amount')) {
$correctionQ = sprintf("UPDATE PaycardTransactions SET amount=%f WHERE
dateID=%s AND refNum='%s'",
$amt,date("Ymd"),$identifier);
$dbTrans->query($correctionQ);
$this->conf->set('paycard_amount', $realAmt);
}
}
// comm successful, check the Authorized, AuthorizationCode and ErrorMsg fields
if (strtolower($status) == 'approved' && $apprNumber != '') {
return PaycardLib::PAYCARD_ERR_OK; // authorization approved, no error
}
if ($errorMsg == '' && isset($json['bank_message'])) {
$errorMsg = $json['bank_message'];
if (isset($json['current_balance'])) {
$errorMsg .= '<br />Current balance: ' . $json['current_balance'];
}
}
// the authorizor gave us some failure code
// authorization failed, response fields in $_SESSION["paycard_response"]
$this->conf->set("boxMsg","Processor error: ".$errorMsg);
if (strlen(trim($errorMsg)) == 0 && strtolower($status) == 'Declined') {
$this->conf-set('boxMsg', 'Transaction declined');
}
return PaycardLib::PAYCARD_ERR_PROC;
}
private function handleResponseVoid($vdResult)
{
$json = json_decode($vdResult['response'], true);
// initialize
$dbTrans = Database::tDataConnect();
// prepare data for the void request
$now = date('Y-m-d H:i:s'); // full timestamp
$validResponse = 1;
$errorMsg = '';
if (isset($json['Error'])) {
foreach ($json['Error']['messages'] as $err) {
$errorMsg .= $err['code'] . ' ';
}
}
$balance = isset($json['valuelink']) && isset($json['valuelink']['current_balance']) ? $json['valuelink']['current_balance'] : 0;
$tranType = $json['transaction_type'];
$status = $json['transaction_status'];
$normalized = $this->getNormalized($status);
$resultCode = ($normalized >= 3) ? 0 : $normalized;
$rMsg = $normalized === 3 ? substr($errorMsg, 0, 100) : $status;
$apprNumber = $json['transaction_id'];
$finishQ = sprintf("UPDATE PaycardTransactions SET
responseDatetime='%s',
seconds=%f,
curlErr=%d,
httpCode=%d,
validResponse=%d,
xResultCode=%d,
xApprovalNumber='%s',
xResponseCode=%d,
xResultMessage='%s',
xTransactionID='%s',
xBalance=%.2f
WHERE paycardTransactionID=%d",
$now,
$vdResult['curlTime'],
$vdResult['curlErr'],
$vdResult['curlHTTP'],
$normalized,
$resultCode,
$apprNumber,
$resultCode,
$rMsg,
$apprNumber,
$balance,
$this->last_paycard_transaction_id
);
$dbTrans->query($finishQ);
if ($vdResult['curlErr'] != CURLE_OK) {
if ($vdResult['curlHTTP'] == '0'){
$this->conf->set("boxMsg","No response from processor<br />The transaction did not go through");
return PaycardLib::PAYCARD_ERR_PROC;
}
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_COMM); // comm error, try again
}
// check for data errors (any failure to parse response XML or echo'd field mismatch)
if ($validResponse != 1) {
// invalid server response, we don't know if the transaction was voided (use carbon)
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_DATA);
}
// put the parsed response into session so the caller, receipt printer, etc can get the data they need
$this->conf->set("paycard_response",array(
'Balance' => strlen($balance) > 0 ? $balance : 0,
));
// comm successful, check the Authorized, AuthorizationCode and ErrorMsg fields
if ($status == 'Approved' && $apprNumber != '') {
return PaycardLib::PAYCARD_ERR_OK; // void successful, no error
}
// the authorizor gave us some failure code
$this->conf->set("boxMsg","PROCESSOR ERROR: " . $errorMsg);
return PaycardLib::PAYCARD_ERR_PROC;
}
private function handleResponseBalance($balResult)
{
$json = json_decode($balResult['response'], true);
if ($balResult['curlErr'] != CURLE_OK) {
if ($balResult['curlHTTP'] == '0'){
$this->conf->set("boxMsg","No response from processor<br />The transaction did not go through");
return PaycardLib::PAYCARD_ERR_PROC;
}
return $this->setErrorMsg(PaycardLib::PAYCARD_ERR_COMM); // comm error, try again
}
$this->conf->set("paycard_response",array());
$resp = array();
$balance = isset($json['current_balance']) ? $json['current_balance'] : 0;
if (strlen($balance) > 0) {
$resp["Balance"] = $balance;
$this->conf->set("paycard_response",$resp);
}
$tranType = $json['transaction_type'];
$cmdStatus = $json['bank_message'];
if ($tranType == '86' && $cmdStatus == 'Approved') {
return PaycardLib::PAYCARD_ERR_OK; // balance checked, no error
}
// the authorizor gave us some failure code
$errorMsg = '';
if (isset($json['Error'])) {
foreach ($json['Error']['messages'] as $err) {
$errorMsg .= $err['code'] . ' ' . $err['description'];
}
}
if ($errorMsg == '' && isset($json['bank_message'])) {
$errorMsg = $json['bank_message'];
}
$this->conf->set("boxMsg","Processor error: ". $errorMsg);
return PaycardLib::PAYCARD_ERR_PROC;
}
private function getPAN()
{
return $this->conf->get("paycard_PAN");
}
private function getTrack2()
{
if ($this->conf->get("training") == 1) {
return false;
}
return $this->conf->get("paycard_tr2");
}
private function getNormalized($status)
{
if ($status === 'Approved') {
return 1;
} elseif ($status === 'Declined') {
return 2;
} elseif ($status === 'Not Processed') {
return 3;
}
return 4;
}
private function getNonce()
{
$ret = '';
for ($i=0; $i<18; $i++) {
$ret .= random_int(0, 9);
}
return $ret;
}
private function getHMAC($payload, $timestamp)
{
$apiSecret = $this->conf->get('ValueLinkHmacKey');
$data = 'POST' . "\n"
. 'application/json' . "\n"
. sha1($payload) . "\n"
. $timestamp . "\n"
. '/transaction/v32';
$hashAlgorithm = "sha1";
$hmac = hash_hmac($hashAlgorithm, $data, $apiSecret, true);
$authorization = base64_encode($hmac);
return $authorization;
}
}