/**
  * @param $httpStatusCode
  * @param DataObject $errorObject
  * @param CallContext $callContext
  * @return DeclinedPaymentException
  *       | DeclinedPayoutException
  *       | DeclinedRefundException
  *       | ValidationException
  *       | AuthorizationException
  *       | ReferenceException
  *       | GlobalCollectException
  *       | ApiException
  */
 public function createException($httpStatusCode, DataObject $errorObject, CallContext $callContext = null)
 {
     if ($errorObject instanceof PaymentErrorResponse && !is_null($errorObject->paymentResult)) {
         return new DeclinedPaymentException($httpStatusCode, $errorObject);
     }
     if ($errorObject instanceof PayoutErrorResponse && !is_null($errorObject->payoutResult)) {
         return new DeclinedPayoutException($httpStatusCode, $errorObject);
     }
     if ($errorObject instanceof RefundErrorResponse && !is_null($errorObject->refundResult)) {
         return new DeclinedRefundException($httpStatusCode, $errorObject);
     }
     if ($httpStatusCode == 400) {
         return new ValidationException($httpStatusCode, $errorObject);
     }
     if ($httpStatusCode == 403) {
         return new AuthorizationException($httpStatusCode, $errorObject);
     }
     if ($httpStatusCode == 409 && $callContext && strlen($callContext->getIdempotenceKey()) > 0 && $this->isIdempotenceError($errorObject)) {
         return new IdempotenceException($httpStatusCode, $errorObject, null, $callContext->getIdempotenceKey(), $callContext->getIdempotenceRequestTimestamp());
     }
     $httpClassCode = floor($httpStatusCode / 100);
     // If a different HTTP status code was sent, then either the user made an error, or the server is in trouble.
     // If the user made an error, the server will give class 4 response. If the server made an error and realises
     // this, it will send an appropriate error message with a class 5 response. It should not be sending other
     // status codes; if it does, we raise an UnexpectedResponseException to signal this.
     switch ($httpClassCode) {
         case 4:
             return new ReferenceException($httpStatusCode, $errorObject);
         case 5:
             return new GlobalCollectException($httpStatusCode, $errorObject);
         default:
             return new ApiException($httpStatusCode, $errorObject);
     }
 }
 public function testCreatePaymentWithIdempotenceKeyFailure()
 {
     $client = $this->getClient();
     $merchantId = self::MERCHANT_ID_FOR_CHALLENGED_PAYMENT_TEST;
     $callContext = new CallContext();
     $dateTimeWitMicroseconds = DateTime::createFromFormat('U.u', microtime(true));
     $callContext->setIdempotenceKey(__FUNCTION__ . '::' . $dateTimeWitMicroseconds->format('Ymd-His-u'));
     $this->assertEmpty($callContext->getIdempotenceRequestTimestamp());
     try {
         $client->merchant($merchantId)->payments()->create($this->getMinimalCreatePaymentRequest(false), $callContext);
         $this->fail('excepted exception');
     } catch (ValidationException $e) {
         $this->assertEmpty($callContext->getIdempotenceRequestTimestamp());
     }
     try {
         $client->merchant($merchantId)->payments()->create($this->getMinimalCreatePaymentRequest(false), $callContext);
         $this->fail('excepted exception');
     } catch (ValidationException $e) {
         $idempotenceRequestTimestamp = $callContext->getIdempotenceRequestTimestamp();
         $this->assertNotEmpty($idempotenceRequestTimestamp);
     }
     try {
         $client->merchant($merchantId)->payments()->create($this->getMinimalCreatePaymentRequest(false), $callContext);
         $this->fail('excepted exception');
     } catch (ValidationException $e) {
         $this->assertEquals($idempotenceRequestTimestamp, $callContext->getIdempotenceRequestTimestamp());
     }
 }