Skip to content

Commit

Permalink
Merge pull request #8 from vimeo/add-pm-no-customer
Browse files Browse the repository at this point in the history
Add support for adding a payment method without specifying the customer
  • Loading branch information
nickyr authored Dec 7, 2016
2 parents 4f00a5d + 0ac8731 commit 1ea622b
Show file tree
Hide file tree
Showing 24 changed files with 533 additions and 132 deletions.
2 changes: 1 addition & 1 deletion src/AbstractVindiciaGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 1 addition & 13 deletions src/Message/AbstractHOARequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
14 changes: 8 additions & 6 deletions src/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down
18 changes: 7 additions & 11 deletions src/Message/CaptureRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion src/Message/CaptureResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
12 changes: 7 additions & 5 deletions src/Message/CompleteHOARequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -80,9 +87,4 @@ public function send()
*/
return parent::send();
}

protected function buildResponse($response)
{
return new CompleteHOAResponse($this, $response);
}
}
51 changes: 47 additions & 4 deletions src/Message/CompleteHOAResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -13,6 +13,7 @@
use Omnipay\Common\Exception\InvalidResponseException;
use Omnipay\Common\Message\RequestInterface;
use Omnipay\Vindicia\Attribute;
use ReflectionClass;

class CompleteHOAResponse extends Response
{
Expand All @@ -32,6 +33,10 @@ class CompleteHOAResponse extends Response
* @var string|null
*/
protected $failureType;
/**
* @var bool
*/
protected $isSuccessful;

// Cached objects:
protected $formValues;
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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);
}

/**
Expand Down
18 changes: 7 additions & 11 deletions src/Message/CreatePayPalSubscriptionRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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);
}
}
67 changes: 42 additions & 25 deletions src/Message/CreatePaymentMethodRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -97,6 +97,7 @@
* } else {
* // error handling
* }
*
* </code>
*/
class CreatePaymentMethodRequest extends AbstractRequest
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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);
}
}
Loading

0 comments on commit 1ea622b

Please sign in to comment.