diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 2ba9fae..f8f6946 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -3,6 +3,7 @@ namespace Omnipay\CyberSourceSimpleOrder\Message; use CybsClient; +use Omnipay\Common\Exception\InvalidRequestException; abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest { @@ -51,11 +52,15 @@ public function sendData($data) $this->getApiHosts() ); - $client = new CybsClient(array(), $options, true); - $requestNvp = $this->arrayToNvp($data); - $reply = $client->runTransaction($requestNvp); + try { + $client = new CybsClient(array(), $options, true); + $requestNvp = $this->arrayToNvp($data); + $reply = $client->runTransaction($requestNvp); - return $this->response = new Response($this, $reply); + return $this->response = new Response($this, $reply); + } catch (\Exception $e) { + throw new InvalidRequestException($e->getMessage()); + } } protected function getResourcePath() diff --git a/src/Message/AuthorizeRequest.php b/src/Message/AuthorizeRequest.php index 97c9ed3..44d082c 100644 --- a/src/Message/AuthorizeRequest.php +++ b/src/Message/AuthorizeRequest.php @@ -11,7 +11,7 @@ public function getData() $data = array( 'ccAuthService_run' => 'true', 'merchantID' => $this->getMerchantId(), - 'merchantReferenceCode' => $this->getTransactionReference(), + 'merchantReferenceCode' => $this->getTransactionId(), 'recurringSubscriptionInfo_subscriptionID' => $this->getToken(), 'purchaseTotals_currency' => $this->getCurrency(), 'purchaseTotals_grandTotalAmount' => $this->getAmount() diff --git a/src/Message/CaptureRequest.php b/src/Message/CaptureRequest.php index 8460ade..f49d473 100644 --- a/src/Message/CaptureRequest.php +++ b/src/Message/CaptureRequest.php @@ -10,9 +10,9 @@ public function getData() { $data = array( 'ccCaptureService_run' => 'true', - 'ccCaptureService_authRequestID' => $this->getTransactionId(), + 'ccCaptureService_authRequestID' => $this->getTransactionReference(), 'merchantID' => $this->getMerchantId(), - 'merchantReferenceCode' => $this->getTransactionReference(), + 'merchantReferenceCode' => $this->getTransactionId(), 'purchaseTotals_currency' => $this->getCurrency(), 'purchaseTotals_grandTotalAmount' => $this->getAmount() ); diff --git a/src/Message/PurchaseRequest.php b/src/Message/PurchaseRequest.php index d56ae10..564e1e7 100644 --- a/src/Message/PurchaseRequest.php +++ b/src/Message/PurchaseRequest.php @@ -12,7 +12,7 @@ public function getData() 'ccAuthService_run' => 'true', 'ccCaptureService_run' => 'true', 'merchantID' => $this->getMerchantId(), - 'merchantReferenceCode' => $this->getTransactionReference(), + 'merchantReferenceCode' => $this->getTransactionId(), 'recurringSubscriptionInfo_subscriptionID' => $this->getToken(), 'purchaseTotals_currency' => $this->getCurrency(), 'purchaseTotals_grandTotalAmount' => $this->getAmount() diff --git a/src/Message/RefundRequest.php b/src/Message/RefundRequest.php index 11e1a53..1f898f5 100644 --- a/src/Message/RefundRequest.php +++ b/src/Message/RefundRequest.php @@ -10,9 +10,9 @@ public function getData() { $data = array( 'ccCreditService_run' => 'true', - 'ccCreditService_captureRequestID' => $this->getTransactionId(), + 'ccCreditService_captureRequestID' => $this->getTransactionReference(), 'merchantID' => $this->getMerchantId(), - 'merchantReferenceCode' => $this->getTransactionReference(), + 'merchantReferenceCode' => $this->getTransactionId(), 'purchaseTotals_currency' => $this->getCurrency(), 'purchaseTotals_grandTotalAmount' => $this->getAmount() ); diff --git a/src/Message/Response.php b/src/Message/Response.php index 4f1f7af..48b6bc9 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -10,10 +10,116 @@ class Response extends AbstractResponse { protected $statusCode; + private $isSuccess = false; + private $errorMessage = ""; + + private static $result_codes = array( + '100' => 'Successful transaction.', + '101' => 'The request is missing one or more required fields.', + '102' => 'One or more fields in the request contains invalid data.', + '110' => 'Only a partial amount was approved.', + '150' => 'Error: General system failure.', + '151' => 'Error: The request was received but there was a server timeout.', + '152' => 'Error: The request was received, but a service did not finish running in time.', + '200' => 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the Address Verification Service (AVS) check.', + '201' => 'The issuing bank has questions about the request.', + '202' => 'Expired card.', + '203' => 'General decline of the card.', + '204' => 'Insufficient funds in the account.', + '205' => 'Stolen or lost card.', + '207' => 'Issuing bank unavailable.', + '208' => 'Inactive card or card not authorized for card-not-present transactions.', + '209' => 'American Express Card Identification Digits (CID) did not match.', + '210' => 'The card has reached the credit limit.', + '211' => 'Invalid CVN.', + '221' => 'The customer matched an entry on the processor\'s negative file.', + '230' => 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the CVN check.', + '231' => 'Invalid credit card number.', + '232' => 'The card type is not accepted by the payment processor.', + '233' => 'General decline by the processor.', + '234' => 'There is a problem with your CyberSource merchant configuration.', + '235' => 'The requested amount exceeds the originally authorized amount.', + '236' => 'Processor failure.', + '237' => 'The authorization has already been reversed.', + '238' => 'The authorization has already been captured.', + '239' => 'The requested transaction amount must match the previous transaction amount.', + '240' => 'The card type sent is invalid or does not correlate with the credit card number.', + '241' => 'The request ID is invalid.', + '242' => 'You requested a capture, but there is no corresponding, unused authorization record.', + '243' => 'The transaction has already been settled or reversed.', + '246' => 'The capture or credit is not voidable because the capture or credit information has laready been submitted to your processor. Or, you requested a void for a type of transaction that cannot be voided.', + '247' => 'You requested a credit for a capture that was previously voided.', + '250' => 'Error: The request was received, but there was a timeout at the payment processor.', + '520' => 'The authorization request was approved by the issuing bank but declined by CyberSource based on your Smart Authorization settings.', + ); + public function __construct(RequestInterface $request, $data) { parent::__construct($request, $data); + $this->crawlResponse(); + } + + private function crawlResponse() + { + if ($this->getData()->decision != 'ACCEPT') { + // Request is missing fields + if ($this->getData()->reasonCode == 101) { + $missing_fields = 'Missing fields: '; + + $fields = $this->preg_grep_keys('/^missingField_\d+$/', (array)$this->getData()); + if (empty($fields)) { + $missing_fields = $missing_fields . 'Unknown'; + } else { + $missing_fields = $missing_fields . implode(', ', $this->vals_from_keys($fields, $this->getData())); + } + + $this->isSuccess = false; + $this->errorMessage = $missing_fields; + return; + } + + // Request contains invalid fields + if ($this->getData()->reasonCode == 102) { + $invalid_fields = 'Invalid fields: '; + + $fields = $this->preg_grep_keys('/^invalidField_\d+$/', (array)$this->getData()); + if (empty($fields)) { + $invalid_fields = $invalid_fields . 'Unknown'; + } else { + $invalid_fields = $invalid_fields . implode(', ', $this->vals_from_keys($fields, $this->getData())); + } + + $this->isSuccess = false; + $this->errorMessage = $invalid_fields; + return; + } + + // Throw error defined by CyberSource + $this->isSuccess = false; + $this->errorMessage = self::$result_codes[$this->getData()->reasonCode ]; + } else { + $this->isSuccess = true; + } + } + + /** + * @param $keys {array} + * @param $input {object} + * @return array + */ + private function vals_from_keys($keys, $input) + { + $vals = []; + foreach ($keys as $key) { + array_push($vals, $input->$key); + } + return $vals; + } + + private function preg_grep_keys($pattern, $input, $flags = 0) + { + return preg_grep($pattern, array_keys($input), $flags); } /** @@ -24,17 +130,12 @@ public function __construct(RequestInterface $request, $data) public function isSuccessful() { // Success if the statusCode is within the 2xx range - return $this->getCode() >= 200 && $this->getCode() < 300; + return $this->isSuccess; } public function getMessage() { - return $this->getData(); - } - - public function getCode() - { - return $this->statusCode = 200; + return $this->errorMessage; } public function getData() diff --git a/src/Message/VoidRequest.php b/src/Message/VoidRequest.php index 6aab1d9..09be315 100644 --- a/src/Message/VoidRequest.php +++ b/src/Message/VoidRequest.php @@ -11,8 +11,8 @@ public function getData() $data = array( 'voidService_run' => 'true', 'merchantID' => $this->getMerchantId(), - 'merchantReferenceCode' => $this->getTransactionReference(), - 'voidService_voidRequestID' => $this->getTransactionId() + 'merchantReferenceCode' => $this->getTransactionId(), + 'voidService_voidRequestID' => $this->getTransactionReference() ); return $data;