diff --git a/src/AbstractVindiciaGateway.php b/src/AbstractVindiciaGateway.php index 7a78bcb..e0fbde1 100644 --- a/src/AbstractVindiciaGateway.php +++ b/src/AbstractVindiciaGateway.php @@ -411,7 +411,7 @@ public function calculateSalesTax(array $parameters = array()) * * @param string $class The request class name * @param array $parameters - * @pram bool $isUpdate default false + * @param bool $isUpdate default false * @return \Omnipay\Vindicia\Message\AbstractRequest */ protected function createRequest($class, array $parameters, $isUpdate = false) diff --git a/src/Message/AbstractHOARequest.php b/src/Message/AbstractHOARequest.php index 0f3058f..e1ca66a 100644 --- a/src/Message/AbstractHOARequest.php +++ b/src/Message/AbstractHOARequest.php @@ -12,7 +12,7 @@ abstract class AbstractHOARequest extends AbstractRequest { - public static $REGULAR_REQUEST_CLASS = 'Omnipay\Vindicia\Message\AbstractRequest'; + protected static $REGULAR_REQUEST_CLASS = '\Omnipay\Vindicia\Message\AbstractRequest'; /** * The corresponding regular (non-HOA) request. This is used to fake @@ -203,18 +203,6 @@ protected function buildPrivateFormValues($keySoFar, $member) ); } return $values; - - - - - // $values = array(); - // foreach ($member as $key => $value) { - // $values = array_merge( - // $this->buildPrivateFormValues($keySoFar . '_' . $key, $value), - // $values - // ); - // } - // return $values; } elseif (isset($member)) { return array(new NameValue($keySoFar, $member)); } else { diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 5c5cf07..6ae85cb 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -75,6 +75,13 @@ abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest */ const DEFAULT_MIN_CHARGEBACK_PROBABILITY = 100; + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\Response'; + /** * Create a new Request * @@ -637,7 +644,7 @@ public function sendData($data) ini_set('soap.wsdl_cache_ttl', $originalWsdlCacheTtl); ini_set('default_socket_timeout', $originalSocketTimeout); - $this->response = $this->buildResponse($response); + $this->response = new static::$RESPONSE_CLASS($this, $response); return $this->response; } @@ -653,11 +660,6 @@ public function send() return parent::send(); } - protected function buildResponse($response) - { - return new Response($this, $response); - } - protected function isUpdate() { return $this->isUpdate; diff --git a/src/Message/CaptureRequest.php b/src/Message/CaptureRequest.php index bbf004c..44542bf 100644 --- a/src/Message/CaptureRequest.php +++ b/src/Message/CaptureRequest.php @@ -83,6 +83,13 @@ */ class CaptureRequest extends AbstractRequest { + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\CaptureResponse'; + /** * The name of the function to be called in Vindicia's API * @@ -130,15 +137,4 @@ public function send() */ return parent::send(); } - - /** - * Use a special response object for Capture requests. - * - * @param object $response - * @return CaptureResponse - */ - protected function buildResponse($response) - { - return new CaptureResponse($this, $response); - } } diff --git a/src/Message/CaptureResponse.php b/src/Message/CaptureResponse.php index 594ef03..eb80bd5 100644 --- a/src/Message/CaptureResponse.php +++ b/src/Message/CaptureResponse.php @@ -26,7 +26,7 @@ public function isSuccessful() // Check all the other response codes that come back and make sure they match up if ($success && (!isset($this->data->return) - || intval($this->data->return->returnCode) !== self::SUCCESS_CODE + || !in_array(intval($this->data->return->returnCode), static::getSuccessCodes(), true) || intval($this->data->qtySuccess) !== 1 || intval($this->data->qtyFail) !== 0 ) diff --git a/src/Message/CompleteHOARequest.php b/src/Message/CompleteHOARequest.php index bf71f61..9a86231 100644 --- a/src/Message/CompleteHOARequest.php +++ b/src/Message/CompleteHOARequest.php @@ -19,6 +19,13 @@ */ class CompleteHOARequest extends AbstractRequest { + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\CompleteHOAResponse'; + /** * The name of the function to be called in Vindicia's API * @@ -80,9 +87,4 @@ public function send() */ return parent::send(); } - - protected function buildResponse($response) - { - return new CompleteHOAResponse($this, $response); - } } diff --git a/src/Message/CompleteHOAResponse.php b/src/Message/CompleteHOAResponse.php index 64e52cc..6465068 100644 --- a/src/Message/CompleteHOAResponse.php +++ b/src/Message/CompleteHOAResponse.php @@ -4,7 +4,7 @@ * they include a response for the method that was actually * called by HOA. If the request itself fails, we return its * error message and code. Otherwise, we return the status - * for the method called by HOA. getFailureType or + * for the method called by HOA. * isRequestFailure and isMethodFailure can be used to * determine if it was a request failure or method failure. */ @@ -13,6 +13,7 @@ use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\RequestInterface; use Omnipay\Vindicia\Attribute; +use ReflectionClass; class CompleteHOAResponse extends Response { @@ -32,6 +33,10 @@ class CompleteHOAResponse extends Response * @var string|null */ protected $failureType; + /** + * @var bool + */ + protected $isSuccessful; // Cached objects: protected $formValues; @@ -60,16 +65,45 @@ public function __construct(RequestInterface $request, $data) if (isset($this->data->session->apiReturn)) { $this->code = $this->data->session->apiReturn->returnCode; $this->message = $this->data->session->apiReturn->returnString; - if (!$this->isSuccessful()) { + + if ($this->wasAuthorize()) { + $requestClass = '\Omnipay\Vindicia\Message\HOAAuthorizeRequest'; + } elseif ($this->wasPurchase()) { + $requestClass = '\Omnipay\Vindicia\Message\HOAPurchaseRequest'; + } elseif ($this->wasCreatePaymentMethod()) { + $requestClass = '\Omnipay\Vindicia\Message\HOACreatePaymentMethodRequest'; + } elseif ($this->wasCreateSubscription()) { + $requestClass = '\Omnipay\Vindicia\Message\HOACreateSubscriptionRequest'; + } else { + // sometimes Vindicia doesn't return any method info on a failure + $this->isSuccessful = false; $this->failureType = self::METHOD_FAILURE; + return; } + + $requestReflection = new ReflectionClass($requestClass); + $regularRequestClassProperty = $requestReflection->getProperty('REGULAR_REQUEST_CLASS'); + $regularRequestClassProperty->setAccessible(true); + $regularRequestClass = $regularRequestClassProperty->getValue(); + $regularRequestClassReflection = new ReflectionClass($regularRequestClass); + $regularRequestResponseClassProperty = $regularRequestClassReflection->getProperty('RESPONSE_CLASS'); + $regularRequestResponseClassProperty->setAccessible(true); + $regularRequestResponseClass = $regularRequestResponseClassProperty->getValue(); + $regularRequestResponseSuccessCodes = $regularRequestResponseClass::getSuccessCodes(); + + $this->isSuccessful = in_array(intval($this->getCode()), $regularRequestResponseSuccessCodes, true); + if (!$this->isSuccessful) { + $this->failureType = self::METHOD_FAILURE; + } + return; } // otherwise, we want the response from the request $this->code = parent::getCode(); $this->message = parent::getMessage(); - if (!$this->isSuccessful()) { + $this->isSuccessful = parent::isSuccessful(); + if (!$this->isSuccessful) { $this->failureType = self::REQUEST_FAILURE; } } @@ -104,6 +138,11 @@ public function getCode() throw new InvalidResponseException('Response has no code.'); } + public function isSuccessful() + { + return $this->isSuccessful; + } + public function getTransaction() { if (isset($this->transaction)) { @@ -154,6 +193,7 @@ public function getSubscription() * method called by HOA failed. Returns null if the request was successful. * * @return string|null + * @deprecated */ public function getFailureType() { @@ -248,7 +288,10 @@ public function wasPurchase() */ public function wasCreatePaymentMethod() { - return $this->getMethod() === 'accountUpdatePaymentMethod'; + return in_array($this->getMethod(), array( + 'accountUpdatePaymentMethod', + 'paymentMethodUpdate' // @todo double check this + ), true); } /** diff --git a/src/Message/CreatePayPalSubscriptionRequest.php b/src/Message/CreatePayPalSubscriptionRequest.php index d651cbc..a6b6c87 100644 --- a/src/Message/CreatePayPalSubscriptionRequest.php +++ b/src/Message/CreatePayPalSubscriptionRequest.php @@ -111,6 +111,13 @@ */ class CreatePayPalSubscriptionRequest extends CreateSubscriptionRequest { + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\CreatePayPalSubscriptionResponse'; + public function getData($paymentMethodType = self::PAYMENT_METHOD_CREDIT_CARD) { $this->validate('returnUrl', 'cancelUrl'); @@ -129,15 +136,4 @@ public function send() */ return parent::send(); } - - /** - * Use a special response object for PayPal subscription requests. - * - * @param object $response - * @return CreatePayPalSubscriptionResponse - */ - protected function buildResponse($response) - { - return new CreatePayPalSubscriptionResponse($this, $response); - } } diff --git a/src/Message/CreatePaymentMethodRequest.php b/src/Message/CreatePaymentMethodRequest.php index 63bdd40..00cc259 100644 --- a/src/Message/CreatePaymentMethodRequest.php +++ b/src/Message/CreatePaymentMethodRequest.php @@ -7,19 +7,19 @@ use Omnipay\Common\Exception\InvalidRequestException; /** - * Create a new payment method and attach it to a customer. Or, update an existing - * payment method. + * Create a new payment method. Or, update an existing payment method. If a customer id + * or reference is provided, the payment method will be attached to that customer. * * Note: You can also create a payment method in the same request as creating a customer. * See Message\CreateCustomerRequest. * * Parameters: - * - customerId: Your identifier for the customer to whom this payment method will belong. - * Either customerId or customerReference is required. - * - customerReference: The gateway's identifier for the customer to whom this payment method - * will belong. Either customerId or customerReference is required. * - card: The card details you're adding. Required. * - paymentMethodId: Your identifier for the payment method. Required. + * - customerId: Your identifier for the customer to whom this payment method will belong. + * If provided, the customer must already exist. + * - customerReference: The gateway's identifier for the customer to whom this payment method + * will belong. If provided, the customer must already exist. * - validate: If set to true, Vindicia will validate the card before adding it (generally * by a 99 cent authorization). Validation may include CVV and AVS validation as well, if set * up with Vindicia. Default is false. @@ -97,6 +97,7 @@ * } else { * // error handling * } + * * */ class CreatePaymentMethodRequest extends AbstractRequest @@ -115,6 +116,13 @@ class CreatePaymentMethodRequest extends AbstractRequest const VALIDATE_CARD = 'Validate'; const SKIP_CARD_VALIDATION = 'Update'; + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\CreatePaymentMethodResponse'; + public function initialize(array $parameters = array()) { $this->cardRequired = true; @@ -144,12 +152,12 @@ public function initialize(array $parameters = array()) */ protected function getFunction() { - return 'updatePaymentMethod'; + return $this->hasCustomer() ? 'updatePaymentMethod' : 'update'; } protected function getObject() { - return self::$CUSTOMER_OBJECT; + return $this->hasCustomer() ? self::$CUSTOMER_OBJECT : self::$PAYMENT_METHOD_OBJECT; } /** @@ -284,29 +292,38 @@ public function getData($paymentMethodType = self::PAYMENT_METHOD_CREDIT_CARD) ); } - $customerId = $this->getCustomerId(); - $customerReference = $this->getCustomerReference(); - if (!$customerId && !$customerReference) { - throw new InvalidRequestException('Either the customerId or customerReference parameter is required.'); - } - if ($this->getCardRequired()) { $this->validate('card'); } - $account = new stdClass(); - $account->merchantAccountId = $customerId; - $account->VID = $customerReference; + $data = array( + 'action' => $this->getFunction(), + 'ignoreAvsPolicy' => $this->getSkipAvsValidation(), + 'ignoreCvnPolicy' => $this->getSkipCvvValidation(), + 'paymentMethod' => $this->buildPaymentMethod($paymentMethodType, true) + ); + + if ($this->hasCustomer()) { + $account = new stdClass(); + $account->merchantAccountId = $this->getCustomerId(); + $account->VID = $this->getCustomerReference(); - $data = array(); - $data['account'] = $account; - $data['paymentMethod'] = $this->buildPaymentMethod($paymentMethodType, true); - $data['action'] = $this->getFunction(); - $data['replaceOnAllAutoBills'] = $this->getUpdateSubscriptions(); - $data['updateBehavior'] = $this->getValidate() ? self::VALIDATE_CARD : self::SKIP_CARD_VALIDATION; - $data['ignoreAvsPolicy'] = $this->getSkipAvsValidation(); - $data['ignoreCvnPolicy'] = $this->getSkipCvvValidation(); + $data['account'] = $account; + $data['replaceOnAllAutoBills'] = $this->getUpdateSubscriptions(); + $data['updateBehavior'] = $this->getValidate() ? self::VALIDATE_CARD : self::SKIP_CARD_VALIDATION; + } else { + $data['validate'] = $this->getValidate(); + $data['minChargebackProbability'] = $this->getMinChargebackProbability(); + $data['replaceOnAllAutoBills'] = $this->getUpdateSubscriptions(); + $data['replaceOnAllChildAutoBills'] = $this->getUpdateSubscriptions(); + $data['sourceIp'] = $this->getIp(); + } return $data; } + + protected function hasCustomer() + { + return ($this->getCustomerId() !== null || $this->getCustomerReference() !== null); + } } diff --git a/src/Message/CreatePaymentMethodResponse.php b/src/Message/CreatePaymentMethodResponse.php new file mode 100644 index 0000000..67da902 --- /dev/null +++ b/src/Message/CreatePaymentMethodResponse.php @@ -0,0 +1,12 @@ + 'paymentMethod', - self::$CUSTOMER_OBJECT => 'account' + $names = array( + self::$PAYMENT_METHOD_OBJECT => 'paymentMethod' ); + + if ($this->hasCustomer()) { + $names[self::$CUSTOMER_OBJECT] = 'account'; + } + + return $names; } public function getValidate() @@ -126,14 +132,44 @@ protected function getMethodParamValues() { $regularRequestData = $this->regularRequest->getData(); - return array( - new NameValue( - 'Account_UpdatePaymentMethod_replaceOnAllAutoBills', - $regularRequestData['replaceOnAllAutoBills'] - ), - new NameValue('Account_UpdatePaymentMethod_updateBehavior', $regularRequestData['updateBehavior']), - new NameValue('Account_UpdatePaymentMethod_ignoreAvsPolicy', $regularRequestData['ignoreAvsPolicy']), - new NameValue('Account_UpdatePaymentMethod_ignoreCvnPolicy', $regularRequestData['ignoreCvnPolicy']) - ); + if ($this->hasCustomer()) { + return array( + new NameValue( + 'Account_UpdatePaymentMethod_replaceOnAllAutoBills', + $regularRequestData['replaceOnAllAutoBills'] + ), + new NameValue('Account_UpdatePaymentMethod_updateBehavior', $regularRequestData['updateBehavior']), + new NameValue('Account_UpdatePaymentMethod_ignoreAvsPolicy', $regularRequestData['ignoreAvsPolicy']), + new NameValue('Account_UpdatePaymentMethod_ignoreCvnPolicy', $regularRequestData['ignoreCvnPolicy']) + ); + } else { + return array( + new NameValue( + 'PaymentMethod_Update_replaceOnAllAutoBills', + $regularRequestData['replaceOnAllAutoBills'] + ), + new NameValue( + 'PaymentMethod_Update_replaceOnAllChildAutoBills', + $regularRequestData['replaceOnAllChildAutoBills'] + ), + new NameValue('PaymentMethod_Update_validate', $regularRequestData['validate']), + new NameValue( + 'PaymentMethod_Update_minChargebackProbability', + $regularRequestData['minChargebackProbability'] + ), + new NameValue('PaymentMethod_Update_sourceIp', $regularRequestData['sourceIp']), + new NameValue('PaymentMethod_Update_ignoreAvsPolicy', $regularRequestData['ignoreAvsPolicy']), + new NameValue('PaymentMethod_Update_ignoreCvnPolicy', $regularRequestData['ignoreCvnPolicy']) + ); + } + } + + protected function hasCustomer() + { + // make it so we can access the regular requests's method since we're + // faking double inheritance + $hasCustomer = new ReflectionMethod(static::$REGULAR_REQUEST_CLASS, 'hasCustomer'); + $hasCustomer->setAccessible(true); + return $hasCustomer->invoke($this->regularRequest, null); } } diff --git a/src/Message/HOACreateSubscriptionRequest.php b/src/Message/HOACreateSubscriptionRequest.php index 2c96aaf..cb577de 100644 --- a/src/Message/HOACreateSubscriptionRequest.php +++ b/src/Message/HOACreateSubscriptionRequest.php @@ -112,7 +112,7 @@ */ class HOACreateSubscriptionRequest extends AbstractHOARequest { - public static $REGULAR_REQUEST_CLASS = 'Omnipay\Vindicia\Message\CreateSubscriptionRequest'; + protected static $REGULAR_REQUEST_CLASS = '\Omnipay\Vindicia\Message\CreateSubscriptionRequest'; protected function getObjectParamNames() { diff --git a/src/Message/HOAPurchaseRequest.php b/src/Message/HOAPurchaseRequest.php index bcb9096..f655979 100644 --- a/src/Message/HOAPurchaseRequest.php +++ b/src/Message/HOAPurchaseRequest.php @@ -83,7 +83,7 @@ */ class HOAPurchaseRequest extends HOAAuthorizeRequest { - public static $REGULAR_REQUEST_CLASS = 'Omnipay\Vindicia\Message\PurchaseRequest'; + protected static $REGULAR_REQUEST_CLASS = '\Omnipay\Vindicia\Message\PurchaseRequest'; protected function getMethodParamValues() { diff --git a/src/Message/PayPalPurchaseRequest.php b/src/Message/PayPalPurchaseRequest.php index 9f8d977..ecf5036 100644 --- a/src/Message/PayPalPurchaseRequest.php +++ b/src/Message/PayPalPurchaseRequest.php @@ -68,6 +68,13 @@ */ class PayPalPurchaseRequest extends PurchaseRequest { + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\PayPalPurchaseResponse'; + public function getData($paymentMethodType = self::PAYMENT_METHOD_CREDIT_CARD) { $this->validate('returnUrl', 'cancelUrl'); @@ -86,15 +93,4 @@ public function send() */ return parent::send(); } - - /** - * Use a special response object for PayPal purchase requests. - * - * @param object $response - * @return PayPalPurchaseResponse - */ - protected function buildResponse($response) - { - return new PayPalPurchaseResponse($this, $response); - } } diff --git a/src/Message/PayPalPurchaseResponse.php b/src/Message/PayPalPurchaseResponse.php index 951847c..8bd9785 100644 --- a/src/Message/PayPalPurchaseResponse.php +++ b/src/Message/PayPalPurchaseResponse.php @@ -13,7 +13,7 @@ class PayPalPurchaseResponse extends Response */ public function isSuccessful() { - return intval($this->getCode()) === self::SUCCESS_CODE && $this->getRedirectUrl(); + return parent::isSuccessful() && $this->getRedirectUrl(); } /** diff --git a/src/Message/RefundRequest.php b/src/Message/RefundRequest.php index 9dbe66e..f6d4d63 100644 --- a/src/Message/RefundRequest.php +++ b/src/Message/RefundRequest.php @@ -100,6 +100,13 @@ */ class RefundRequest extends AbstractRequest { + /** + * The class to use for the response. + * + * @var string + */ + protected static $RESPONSE_CLASS = '\Omnipay\Vindicia\Message\RefundResponse'; + /** * The name of the function to be called in Vindicia's API * @@ -235,15 +242,4 @@ public function send() */ return parent::send(); } - - /** - * Use a special response object for Refund requests. - * - * @param object $response - * @return RefundResponse - */ - protected function buildResponse($response) - { - return new RefundResponse($this, $response); - } } diff --git a/src/Message/Response.php b/src/Message/Response.php index 976bfd7..aada09d 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -9,7 +9,7 @@ class Response extends AbstractResponse { - const SUCCESS_CODE = 200; + protected static $SUCCESS_CODES = array(200); protected $objectHelper; @@ -47,7 +47,7 @@ public function __construct(RequestInterface $request, $data) */ public function isSuccessful() { - return intval($this->getCode()) === self::SUCCESS_CODE; + return in_array(intval($this->getCode()), static::getSuccessCodes(), true); } /** @@ -462,4 +462,14 @@ public function getRequest() */ return parent::getRequest(); } + + /** + * Get the codes that indicate success + * + * @return array + */ + public static function getSuccessCodes() + { + return static::$SUCCESS_CODES; + } } diff --git a/src/TestFramework/Mocker.php b/src/TestFramework/Mocker.php index cec4c2f..2f94e9f 100644 --- a/src/TestFramework/Mocker.php +++ b/src/TestFramework/Mocker.php @@ -23,8 +23,10 @@ public static function mockHOARequest($requestClass) $regularRequestProperty = $requestReflection->getProperty('regularRequest'); $regularRequestProperty->setAccessible(true); // the regularRequest instance object must be mocked as well - $regularRequest = self::mock($requestClass::$REGULAR_REQUEST_CLASS) - ->makePartial()->shouldAllowMockingProtectedMethods(); + $regularRequestClassProperty = $requestReflection->getProperty('REGULAR_REQUEST_CLASS'); + $regularRequestClassProperty->setAccessible(true); + $regularRequestClass = $regularRequestClassProperty->getValue(); + $regularRequest = self::mock($regularRequestClass)->makePartial()->shouldAllowMockingProtectedMethods(); $regularRequestProperty->setValue($request, $regularRequest); return $request; diff --git a/tests/Message/AbstractRequestTest.php b/tests/Message/AbstractRequestTest.php index fb60828..acccbca 100644 --- a/tests/Message/AbstractRequestTest.php +++ b/tests/Message/AbstractRequestTest.php @@ -301,7 +301,6 @@ public function testSendData() TestableSoapClient::setNextResponse(new stdClass()); $this->request->shouldReceive('getObject')->andReturn($object); - $this->request->shouldReceive('buildResponse')->andReturn(null); $this->request->shouldReceive('getTestMode')->andReturn(true); $this->request->shouldReceive('getUsername')->andReturn($this->username); $this->request->shouldReceive('getPassword')->andReturn($this->password); diff --git a/tests/Message/CreatePaymentMethodRequestTest.php b/tests/Message/CreatePaymentMethodRequestTest.php index 47d8a0e..291fb15 100644 --- a/tests/Message/CreatePaymentMethodRequestTest.php +++ b/tests/Message/CreatePaymentMethodRequestTest.php @@ -189,24 +189,82 @@ public function testGetDataDoNotUpdateSubscriptions() $this->assertSame('updatePaymentMethod', $data['action']); } - /** - * @expectedException \Omnipay\Common\Exception\InvalidRequestException - * @expectedExceptionMessage The paymentMethodId parameter is required - */ - public function testPaymentMethodIdRequired() + public function testGetDataNoCustomer() { - $this->request->setPaymentMethodId(null); - $this->request->getData(); + $this->request->setCustomerId(null)->setCustomerReference(null); + $data = $this->request->getData(); + + $this->assertSame($this->paymentMethodId, $data['paymentMethod']->merchantPaymentMethodId); + $this->assertSame($this->paymentMethodReference, $data['paymentMethod']->VID); + $this->assertSame($this->card['number'], $data['paymentMethod']->creditCard->account); + $this->assertSame($this->card['expiryYear'], substr($data['paymentMethod']->creditCard->expirationDate, 0, 4)); + $this->assertSame(intval($this->card['expiryMonth']), intval(substr($data['paymentMethod']->creditCard->expirationDate, 4))); + $this->assertTrue(in_array(new NameValue('CVN', $this->card['cvv']), $data['paymentMethod']->nameValues)); + $this->assertSame($this->card['postcode'], $data['paymentMethod']->billingAddress->postalCode); + $this->assertSame($this->card['country'], $data['paymentMethod']->billingAddress->country); + $this->assertSame('CreditCard', $data['paymentMethod']->type); + $this->assertFalse(isset($data['account'])); + + $numAttributes = count($this->attributes); + $this->assertSame($numAttributes + 1, count($data['paymentMethod']->nameValues)); // +1 accounts for CVV + for ($i = 0; $i < $numAttributes; $i++) { + $this->assertSame($this->attributes[$i]['name'], $data['paymentMethod']->nameValues[$i]->name); + $this->assertSame($this->attributes[$i]['value'], $data['paymentMethod']->nameValues[$i]->value); + } + + $this->assertFalse($data['validate']); + $this->assertFalse($data['ignoreAvsPolicy']); + $this->assertFalse($data['ignoreCvnPolicy']); + $this->assertTrue($data['replaceOnAllAutoBills']); + $this->assertTrue($data['replaceOnAllChildAutoBills']); + $this->assertSame('update', $data['action']); + } + + public function testGetDataNoCustomerWithValidation() + { + $this->request->setCustomerId(null)->setCustomerReference(null); + $skipAvsValidation = $this->faker->bool(); + $skipCvvValidation = $this->faker->bool(); + $data = $this->request->setValidate(true) + ->setSkipAvsValidation($skipAvsValidation) + ->setSkipCvvValidation($skipCvvValidation) + ->getData(); + + $this->assertSame($this->paymentMethodId, $data['paymentMethod']->merchantPaymentMethodId); + $this->assertSame($this->paymentMethodReference, $data['paymentMethod']->VID); + $this->assertSame($this->card['number'], $data['paymentMethod']->creditCard->account); + $this->assertSame($this->card['expiryYear'], substr($data['paymentMethod']->creditCard->expirationDate, 0, 4)); + $this->assertSame(intval($this->card['expiryMonth']), intval(substr($data['paymentMethod']->creditCard->expirationDate, 4))); + $this->assertFalse(isset($data['account'])); + $this->assertTrue($data['validate']); + $this->assertSame($skipAvsValidation, $data['ignoreAvsPolicy']); + $this->assertSame($skipCvvValidation, $data['ignoreCvnPolicy']); + $this->assertSame('update', $data['action']); + } + + public function testGetDataNoCustomerDoNotUpdateSubscriptions() + { + $this->request->setCustomerId(null)->setCustomerReference(null); + $data = $this->request->setUpdateSubscriptions(false)->getData(); + + $this->assertSame($this->paymentMethodId, $data['paymentMethod']->merchantPaymentMethodId); + $this->assertSame($this->paymentMethodReference, $data['paymentMethod']->VID); + $this->assertSame($this->card['number'], $data['paymentMethod']->creditCard->account); + $this->assertSame($this->card['expiryYear'], substr($data['paymentMethod']->creditCard->expirationDate, 0, 4)); + $this->assertSame(intval($this->card['expiryMonth']), intval(substr($data['paymentMethod']->creditCard->expirationDate, 4))); + $this->assertFalse(isset($data['account'])); + $this->assertFalse($data['replaceOnAllAutoBills']); + $this->assertFalse($data['replaceOnAllChildAutoBills']); + $this->assertSame('update', $data['action']); } /** * @expectedException \Omnipay\Common\Exception\InvalidRequestException - * @expectedExceptionMessage Either the customerId or customerReference parameter is required. + * @expectedExceptionMessage The paymentMethodId parameter is required */ - public function testCustomerIdOrReferenceRequired() + public function testPaymentMethodIdRequired() { - $this->request->setCustomerId(null); - $this->request->setCustomerReference(null); + $this->request->setPaymentMethodId(null); $this->request->getData(); } @@ -256,6 +314,59 @@ public function testSendSuccess() $this->assertSame('https://soap.prodtest.sj.vindicia.com/18.0/Account.wsdl', $this->getLastEndpoint()); } + public function testSendNoCustomerSuccess() + { + $this->request->setCustomerId(null)->setCustomerReference(null); + + $this->setMockSoapResponse('CreatePaymentMethodNoCustomerSuccess.xml', array( + 'CARD_FIRST_SIX' => substr($this->card['number'], 0, 6), + 'CARD_LAST_FOUR' => substr($this->card['number'], -4), + 'EXPIRY_MONTH' => $this->card['expiryMonth'], + 'EXPIRY_YEAR' => $this->card['expiryYear'], + 'PAYMENT_METHOD_ID' => $this->paymentMethodId, + 'PAYMENT_METHOD_REFERENCE' => $this->paymentMethodReference + )); + + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertFalse($response->isPending()); + $this->assertSame('OK', $response->getMessage()); + $this->assertSame($this->paymentMethodId, $response->getPaymentMethodId()); + $this->assertSame($this->paymentMethodReference, $response->getPaymentMethodReference()); + + $this->assertSame('https://soap.prodtest.sj.vindicia.com/18.0/PaymentMethod.wsdl', $this->getLastEndpoint()); + } + + /** + * Check that a different success code still works + */ + public function testSendNoCustomer228Success() + { + $this->request->setCustomerId(null)->setCustomerReference(null); + + $this->setMockSoapResponse('CreatePaymentMethodNoCustomer228Success.xml', array( + 'CARD_FIRST_SIX' => substr($this->card['number'], 0, 6), + 'CARD_LAST_FOUR' => substr($this->card['number'], -4), + 'EXPIRY_MONTH' => $this->card['expiryMonth'], + 'EXPIRY_YEAR' => $this->card['expiryYear'], + 'PAYMENT_METHOD_ID' => $this->paymentMethodId, + 'PAYMENT_METHOD_REFERENCE' => $this->paymentMethodReference + )); + + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertFalse($response->isPending()); + $this->assertSame('Payment method saved but missing associated account - unable to replace on autobills ', $response->getMessage()); + $this->assertSame($this->paymentMethodId, $response->getPaymentMethodId()); + $this->assertSame($this->paymentMethodReference, $response->getPaymentMethodReference()); + + $this->assertSame('https://soap.prodtest.sj.vindicia.com/18.0/PaymentMethod.wsdl', $this->getLastEndpoint()); + } + public function testSendFailure() { $this->setMockSoapResponse('CreatePaymentMethodFailure.xml', array( diff --git a/tests/Message/HOACreatePaymentMethodRequestTest.php b/tests/Message/HOACreatePaymentMethodRequestTest.php index 8c28cb7..a2e5284 100644 --- a/tests/Message/HOACreatePaymentMethodRequestTest.php +++ b/tests/Message/HOACreatePaymentMethodRequestTest.php @@ -159,6 +159,67 @@ public function testGetData() new NameValue('Account_UpdatePaymentMethod_updateBehavior', $this->validate ? CreatePaymentMethodRequest::VALIDATE_CARD : CreatePaymentMethodRequest::SKIP_CARD_VALIDATION), $data['session']->methodParamValues )); + $this->assertTrue(in_array( + new NameValue('Account_UpdatePaymentMethod_replaceOnAllAutoBills', true), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('Account_UpdatePaymentMethod_ignoreAvsPolicy', false), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('Account_UpdatePaymentMethod_ignoreCvnPolicy', false), + $data['session']->methodParamValues + )); + + $this->assertSame('initialize', $data['action']); + } + + public function testGetDataNoCustomer() + { + $this->request->setCustomerId(null)->setCustomerReference(null); + $data = $this->request->getData(); + + $this->assertSame($this->returnUrl, $data['session']->returnURL); + $this->assertSame($this->errorUrl, $data['session']->errorURL); + $this->assertSame('PaymentMethod_update', $data['session']->method); + $this->assertSame($this->ip, $data['session']->ipAddress); + $numHOAAttributes = count($this->HOAAttributes); + $this->assertSame($numHOAAttributes, count($data['session']->nameValues)); + for ($i = 0; $i < $numHOAAttributes; $i++) { + $this->assertSame($this->HOAAttributes[$i]['name'], $data['session']->nameValues[$i]->name); + $this->assertSame($this->HOAAttributes[$i]['value'], $data['session']->nameValues[$i]->value); + } + $this->assertSame(AbstractRequest::API_VERSION, $data['session']->version); + + $this->assertTrue(in_array( + new NameValue('vin_PaymentMethod_merchantPaymentMethodId', $this->paymentMethodId), + $data['session']->privateFormValues + )); + $this->assertTrue(in_array( + new NameValue('vin_PaymentMethod_VID', $this->paymentMethodReference), + $data['session']->privateFormValues + )); + $this->assertTrue(in_array( + new NameValue('PaymentMethod_Update_validate', $this->validate), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('PaymentMethod_Update_replaceOnAllAutoBills', true), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('PaymentMethod_Update_replaceOnAllChildAutoBills', true), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('PaymentMethod_Update_ignoreAvsPolicy', false), + $data['session']->methodParamValues + )); + $this->assertTrue(in_array( + new NameValue('PaymentMethod_Update_ignoreCvnPolicy', false), + $data['session']->methodParamValues + )); $this->assertSame('initialize', $data['action']); } diff --git a/tests/Mock/CreatePaymentMethodNoCustomer228Success.xml b/tests/Mock/CreatePaymentMethodNoCustomer228Success.xml new file mode 100644 index 0000000..99e8da1 --- /dev/null +++ b/tests/Mock/CreatePaymentMethodNoCustomer228Success.xml @@ -0,0 +1,66 @@ + + + + + 228 + 1234567890abcdef1234567890abcdef + Payment method saved but missing associated account - unable to replace on autobills + + + [PAYMENT_METHOD_REFERENCE] + CreditCard + + [CARD_FIRST_SIX]XXXXXX[CARD_LAST_FOUR] + [CARD_FIRST_SIX] + [CARD_LAST_FOUR] + 16 + [EXPIRY_YEAR][EXPIRY_MONTH] + + 0 + 0 + 0 + 0 + 0 + 0 + USA + 0 + 0 + + 0123456789fedcba0123456789fedcba + + [PAYMENT_METHOD_ID] + 0 + 1 + + 1 + 1 + -1 + + AuthorizedForValidation + 2016-12-07T06:30:40-08:00 + CreditCard + + [AUTHORIZATION_CODE] + [AVS_CODE] + + 0 + 0 + 0 + 0 + 0 + 0 + [COUNTRY] + 0 + 0 + + + + + + diff --git a/tests/Mock/CreatePaymentMethodNoCustomerSuccess.xml b/tests/Mock/CreatePaymentMethodNoCustomerSuccess.xml new file mode 100644 index 0000000..1120838 --- /dev/null +++ b/tests/Mock/CreatePaymentMethodNoCustomerSuccess.xml @@ -0,0 +1,68 @@ + + + + + + 200 + 1234567890abcdef1234567890abcdef + OK + + + [PAYMENT_METHOD_REFERENCE] + CreditCard + + [CARD_FIRST_SIX]XXXXXX[CARD_LAST_FOUR] + [CARD_FIRST_SIX] + [CARD_LAST_FOUR] + 16 + [EXPIRY_YEAR][EXPIRY_MONTH] + + 0 + 0 + 0 + 0 + 0 + 0 + USA + 0 + 0 + + 0123456789fedcba0123456789fedcba + + [PAYMENT_METHOD_ID] + 0 + 1 + + 0 + 1 + -1 + + AuthorizedForValidation + 2016-12-07T06:36:09-08:00 + CreditCard + + [AUTHORIZATION_CODE] + [AVS_CODE] + + 0 + 0 + 0 + 0 + 0 + 0 + [COUNTRY] + 0 + 0 + + + PartialMatch + + + +