diff --git a/composer.json b/composer.json index e0e0f3f..ae5bc44 100644 --- a/composer.json +++ b/composer.json @@ -26,14 +26,14 @@ "psr-4": { "Omnipay\\NMI\\" : "src/" } }, "require": { - "omnipay/common": "~2.0" + "omnipay/common": "^3" }, "require-dev": { - "omnipay/tests": "~2.0" + "omnipay/tests": "^3" }, "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } } } diff --git a/src/DirectPostGateway.php b/src/DirectPostGateway.php index affc84a..a8425e3 100644 --- a/src/DirectPostGateway.php +++ b/src/DirectPostGateway.php @@ -363,7 +363,7 @@ public function credit(array $parameters = array()) /** * @param array $parameters - * @return \Omnipay\NMI\Message\CreateCardRequest + * @return \Omnipay\NMI\Message\DirectPostCreateCardRequest */ public function createCard(array $parameters = array()) { @@ -372,7 +372,7 @@ public function createCard(array $parameters = array()) /** * @param array $parameters - * @return \Omnipay\NMI\Message\UpdateCardRequest + * @return \Omnipay\NMI\Message\DirectPostUpdateCardRequest */ public function updateCard(array $parameters = array()) { @@ -381,7 +381,7 @@ public function updateCard(array $parameters = array()) /** * @param array $parameters - * @return \Omnipay\NMI\Message\DeleteCardRequest + * @return \Omnipay\NMI\Message\DirectPostDeleteCardRequest */ public function deleteCard(array $parameters = array()) { diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 8b31722..0eb3f65 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -326,9 +326,14 @@ protected function getShippingData() public function sendData($data) { - $httpResponse = $this->httpClient->post($this->getEndpoint(), null, $data)->send(); + $httpResponse = $this->httpClient->request( + 'POST', + $this->getEndpoint(), + ['Content-Type' => 'application/x-www-form-urlencoded'], + http_build_query($data, '', '&') + ); - return $this->response = new DirectPostResponse($this, $httpResponse->getBody()); + return $this->response = new DirectPostResponse($this, $httpResponse->getBody()->getContents()); } public function setEndpoint($value) @@ -338,6 +343,6 @@ public function setEndpoint($value) public function getEndpoint() { - return $this->endpoint; + return $this->getParameter('endpoint') ?: $this->endpoint; } } diff --git a/src/Message/DirectPostAuthRequest.php b/src/Message/DirectPostAuthRequest.php index 24f8b6c..917aedd 100644 --- a/src/Message/DirectPostAuthRequest.php +++ b/src/Message/DirectPostAuthRequest.php @@ -8,6 +8,82 @@ class DirectPostAuthRequest extends AbstractRequest { protected $type = 'auth'; + /** + * @return string + */ + public function getMerchantDefinedField_1() + { + return $this->getParameter('merchant_defined_field_1'); + } + + /** + * Sets the first merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_1($value) + { + return $this->setParameter('merchant_defined_field_1', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_2() + { + return $this->getParameter('merchant_defined_field_2'); + } + + /** + * Sets the second merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_2($value) + { + return $this->setParameter('merchant_defined_field_2', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_3() + { + return $this->getParameter('merchant_defined_field_3'); + } + + /** + * Sets the third merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_3($value) + { + return $this->setParameter('merchant_defined_field_3', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_4() + { + return $this->getParameter('merchant_defined_field_4'); + } + + /** + * Sets the fourth merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_4($value) + { + return $this->setParameter('merchant_defined_field_4', $value); + } + public function getData() { $this->validate('amount'); @@ -15,6 +91,22 @@ public function getData() $data = $this->getBaseData(); $data['amount'] = $this->getAmount(); + if ($this->getMerchantDefinedField_1()) { + $data['merchant_defined_field_1'] = $this->getMerchantDefinedField_1(); + } + + if ($this->getMerchantDefinedField_2()) { + $data['merchant_defined_field_2'] = $this->getMerchantDefinedField_2(); + } + + if ($this->getMerchantDefinedField_3()) { + $data['merchant_defined_field_3'] = $this->getMerchantDefinedField_3(); + } + + if ($this->getMerchantDefinedField_4()) { + $data['merchant_defined_field_4'] = $this->getMerchantDefinedField_4(); + } + if ($this->getCardReference()) { $data['customer_vault_id'] = $this->getCardReference(); diff --git a/src/Message/ThreeStepRedirectAbstractRequest.php b/src/Message/ThreeStepRedirectAbstractRequest.php new file mode 100644 index 0000000..0296ef9 --- /dev/null +++ b/src/Message/ThreeStepRedirectAbstractRequest.php @@ -0,0 +1,342 @@ +getParameter('api_key'); + } + + /** + * @param string + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function setApiKey($value) + { + return $this->setParameter('api_key', $value); + } + + /** + * @return string + */ + public function getRedirectUrl() + { + return $this->getParameter('redirect_url'); + } + + /** + * @param string + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function setRedirectUrl($value) + { + return $this->setParameter('redirect_url', $value); + } + + /** + * @return string + */ + public function getTokenId() + { + return $this->getParameter('token_id'); + } + + /** + * @param string + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function setTokenId($value) + { + return $this->setParameter('token_id', $value); + } + + /** + * Sets the card. + * + * @param CreditCard $value + * @return AbstractRequest Provides a fluent interface + */ + public function setCard($value) + { + if (!$value instanceof CreditCard) { + $value = new CreditCard($value); + } + + return $this->setParameter('card', $value); + } + + /** + * @return string + */ + public function getSecCode() + { + return $this->getParameter('sec_code'); + } + + /** + * @param string + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function setSecCode($value) + { + return $this->setParameter('sec_code', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_1() + { + return $this->getParameter('merchant_defined_field_1'); + } + + /** + * Sets the first merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_1($value) + { + return $this->setParameter('merchant_defined_field_1', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_2() + { + return $this->getParameter('merchant_defined_field_2'); + } + + /** + * Sets the second merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_2($value) + { + return $this->setParameter('merchant_defined_field_2', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_3() + { + return $this->getParameter('merchant_defined_field_3'); + } + + /** + * Sets the third merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_3($value) + { + return $this->setParameter('merchant_defined_field_3', $value); + } + + /** + * @return string + */ + public function getMerchantDefinedField_4() + { + return $this->getParameter('merchant_defined_field_4'); + } + + /** + * Sets the fourth merchant defined field. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setMerchantDefinedField_4($value) + { + return $this->setParameter('merchant_defined_field_4', $value); + } + + /** + * @return array + */ + protected function getOrderData() + { + $data = array(); + + $data['order-id'] = $this->getOrderId(); + $data['order-description'] = $this->getOrderDescription(); + $data['tax-amount'] = $this->getTax(); + $data['shipping-amount'] = $this->getShipping(); + $data['po-number'] = $this->getPONumber(); + $data['ip-address'] = $this->getClientIp(); + + if ($this->getCurrency()) { + $data['currency'] = $this->getCurrency(); + } + + if ($this->getSecCode()) { + $data['sec-code'] = $this->getSecCode(); + } + + return $data; + } + + /** + * @return array + */ + protected function getBillingData() + { + $data = array(); + + if ($card = $this->getCard()) { + $data['billing'] = array( + 'first-name' => $card->getBillingFirstName(), + 'last-name' => $card->getBillingLastName(), + 'address1' => $card->getBillingAddress1(), + 'city' => $card->getBillingCity(), + 'state' => $card->getBillingState(), + 'postal' => $card->getBillingPostcode(), + 'country' => $card->getBillingCountry(), + 'phone' => $card->getBillingPhone(), + 'email' => $card->getEmail(), + 'company' => $card->getBillingCompany(), + 'address2' => $card->getBillingAddress2(), + 'fax' => $card->getBillingFax(), + ); + } + + return $data; + } + + /** + * @return array + */ + protected function getShippingData() + { + $data = array(); + + if ($card = $this->getCard()) { + $data['shipping'] = array( + 'first-name' => $card->getShippingFirstName(), + 'last-name' => $card->getShippingLastName(), + 'address1' => $card->getShippingAddress1(), + 'city' => $card->getShippingCity(), + 'state' => $card->getShippingState(), + 'postal' => $card->getShippingPostcode(), + 'country' => $card->getShippingCountry(), + 'email' => $card->getEmail(), + 'company' => $card->getShippingCompany(), + 'address2' => $card->getShippingAddress2(), + ); + } + + return $data; + } + + /** + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectResponse + */ + public function sendData($data) + { + $document = new SimpleXMLElement('<'.$this->type.'/>'); + $this->arrayToXml($document, $data); + + $httpResponse = $this->httpClient->request( + 'POST', + $this->getEndpoint(), + array( + 'Content-Type' => 'text/xml', + 'User-Agent' => 'Omnipay', + ), + $document->asXML() + ); + + $xml = static::xmlDecode($httpResponse); + + return $this->response = new ThreeStepRedirectResponse($this, $xml); + } + + /** + * Parse the XML response body and return a \SimpleXMLElement. + * + * In order to prevent XXE attacks, this method disables loading external + * entities. If you rely on external entities, then you must parse the + * XML response manually by accessing the response body directly. + * + * Copied from Response->xml() in Guzzle3 (copyright @mtdowling) + * @link https://github.com/guzzle/guzzle3/blob/v3.9.3/src/Guzzle/Http/Message/Response.php + * + * @param string|ResponseInterface $response + * @return \SimpleXMLElement + * @throws RuntimeException if the response body is not in XML format + * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html + * + */ + public static function xmlDecode($response) + { + if ($response instanceof \Psr\Http\Message\ResponseInterface) { + $body = $response->getBody()->__toString(); + } else { + $body = (string) $response; + } + + $errorMessage = null; + $internalErrors = libxml_use_internal_errors(true); + $disableEntities = libxml_disable_entity_loader(true); + libxml_clear_errors(); + + try { + $xml = new \SimpleXMLElement((string) $body ?: '', LIBXML_NONET); + } catch (\Exception $e) { + $errorMessage = $e->getMessage(); + } + + libxml_clear_errors(); + libxml_use_internal_errors($internalErrors); + libxml_disable_entity_loader($disableEntities); + + if ($errorMessage !== null) { + throw new \InvalidArgumentException('SimpleXML error: ' . $errorMessage); + } + + return $xml; + } + + /** + * @param \SimpleXMLElement + * @param array + * @return void + */ + private function arrayToXml(SimpleXMLElement $parent, array $data) + { + foreach ($data as $name => $value) { + if (is_array($value)) { + $child = $parent->addChild($name); + $this->arrayToXml($child, $value); + } + else { + $parent->addChild($name, htmlspecialchars($value)); + } + } + } +} diff --git a/src/Message/ThreeStepRedirectAuthRequest.php b/src/Message/ThreeStepRedirectAuthRequest.php new file mode 100644 index 0000000..9fcd796 --- /dev/null +++ b/src/Message/ThreeStepRedirectAuthRequest.php @@ -0,0 +1,138 @@ +setParameter('dup_seconds', $value); + } + + /** + * @return string + */ + public function getDupSeconds() + { + return $this->getParameter('dup_seconds'); + } + + /** + * Sets the add customer. + * + * @param boolean + * @return AbstractRequest Provides a fluent interface + */ + public function setAddCustomer($value) + { + return $this->setParameter('add_customer', $value); + } + + /** + * @return string + */ + public function getAddCustomer() + { + return $this->getParameter('add_customer'); + } + + /** + * Sets the update customer. + * + * @param string + * @return AbstractRequest Provides a fluent interface + */ + public function setUpdateCustomer($value) + { + return $this->setParameter('update_customer', $value); + } + + /** + * @return string + */ + public function getUpdateCustomer() + { + return $this->getParameter('update_customer'); + } + + /** + * @return array + */ + public function getData() + { + $this->validate('amount'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'redirect-url' => $this->getRedirectUrl(), + 'amount' => $this->getAmount(), + ); + + if ($this->getCurrency()) { + $data['currency'] = $this->getCurrency(); + } + + if ($this->getDupSeconds()) { + $data['dup-seconds'] = $this->getDupSeconds(); + } + + if ($this->getMerchantDefinedField_1()) { + $data['merchant-defined-field-1'] = $this->getMerchantDefinedField_1(); + } + + if ($this->getMerchantDefinedField_2()) { + $data['merchant-defined-field-2'] = $this->getMerchantDefinedField_2(); + } + + if ($this->getMerchantDefinedField_3()) { + $data['merchant-defined-field-3'] = $this->getMerchantDefinedField_3(); + } + + if ($this->getMerchantDefinedField_4()) { + $data['merchant-defined-field-4'] = $this->getMerchantDefinedField_4(); + } + + if ($this->getCardReference()) { + $data['customer-vault-id'] = $this->getCardReference(); + + // Customer Vault operations can be completed using a single Direct XML request to the gateway. + // None of these operations submit sensitive payment information and theorefore do not require + // any Three Step Redirect functionlity. + unset($data['redirect-url']); + } + else { + $data = array_merge( + $data, + $this->getOrderData(), + $this->getBillingData(), + $this->getShippingData() + ); + + if ($this->getAddCustomer()) { + $data['add-customer'] = []; + } + + if ($this->getUpdateCustomer()) { + $data['update-customer'] = [ + 'customer-vault-id' => $this->getUpdateCustomer(), + ]; + } + } + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectCaptureRequest.php b/src/Message/ThreeStepRedirectCaptureRequest.php new file mode 100644 index 0000000..8f7ea89 --- /dev/null +++ b/src/Message/ThreeStepRedirectCaptureRequest.php @@ -0,0 +1,49 @@ +validate('transactionReference'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'transaction-id' => $this->getTransactionReference(), + ); + + if ($this->getAmount() > 0) { + $data['amount'] = $this->getAmount(); + } + + if ($this->getMerchantDefinedField_1()) { + $data['merchant-defined-field-1'] = $this->getMerchantDefinedField_1(); + } + + if ($this->getMerchantDefinedField_2()) { + $data['merchant-defined-field-2'] = $this->getMerchantDefinedField_2(); + } + + if ($this->getMerchantDefinedField_3()) { + $data['merchant-defined-field-3'] = $this->getMerchantDefinedField_3(); + } + + if ($this->getMerchantDefinedField_4()) { + $data['merchant-defined-field-4'] = $this->getMerchantDefinedField_4(); + } + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectCompleteActionRequest.php b/src/Message/ThreeStepRedirectCompleteActionRequest.php new file mode 100644 index 0000000..57d57a0 --- /dev/null +++ b/src/Message/ThreeStepRedirectCompleteActionRequest.php @@ -0,0 +1,29 @@ +validate('token_id'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'token-id' => $this->getTokenId(), + ); + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectCreateCardRequest.php b/src/Message/ThreeStepRedirectCreateCardRequest.php new file mode 100644 index 0000000..89da02d --- /dev/null +++ b/src/Message/ThreeStepRedirectCreateCardRequest.php @@ -0,0 +1,35 @@ +validate('card'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'redirect-url' => $this->getRedirectUrl(), + ); + + $data = array_merge( + $data, + $this->getBillingData(), + $this->getShippingData() + ); + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectCreditRequest.php b/src/Message/ThreeStepRedirectCreditRequest.php new file mode 100644 index 0000000..b44164a --- /dev/null +++ b/src/Message/ThreeStepRedirectCreditRequest.php @@ -0,0 +1,14 @@ +validate('cardReference'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'redirect-url' => $this->getRedirectUrl(), + 'customer-vault-id' => $this->getCardReference(), + ); + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectRefundRequest.php b/src/Message/ThreeStepRedirectRefundRequest.php new file mode 100644 index 0000000..8788169 --- /dev/null +++ b/src/Message/ThreeStepRedirectRefundRequest.php @@ -0,0 +1,14 @@ +request = $request; + $this->data = $data; + } + + /** + * @return boolean + */ + public function isSuccessful() + { + return '1' === $this->getCode(); + } + + /** + * @return string + */ + public function getCode() + { + return trim($this->data->{'result'}); + } + + /** + * @return string + */ + public function getResponseCode() + { + return trim($this->data->{'result-code'}); + } + + /** + * @return string + */ + public function getMessage() + { + return trim($this->data->{'result-text'}); + } + + public function getAuthorizationCode() + { + return trim($this->data->{'authorization-code'}); + } + + /** + * @return string + */ + public function getAVSResponse() + { + return trim($this->data->{'avs-result'}); + } + + /** + * @return string + */ + public function getCVVResponse() + { + return trim($this->data->{'cvv-result'}); + } + + /** + * @return string + */ + public function getOrderId() + { + return trim($this->data->{'order-id'}); + } + + /** + * @return string + */ + public function getTransactionReference() + { + return trim($this->data->{'transaction-id'}); + } + + /** + * @return string|null + */ + public function getCardReference() + { + if (isset($this->data->{'customer-vault-id'})) { + return trim($this->data->{'customer-vault-id'}); + } + + return null; + } + + /** + * @return string|null + */ + public function getFormUrl() + { + if (isset($this->data->{'form-url'})) { + return trim($this->data->{'form-url'}); + } + + return null; + } +} diff --git a/src/Message/ThreeStepRedirectSaleRequest.php b/src/Message/ThreeStepRedirectSaleRequest.php new file mode 100644 index 0000000..3b1599c --- /dev/null +++ b/src/Message/ThreeStepRedirectSaleRequest.php @@ -0,0 +1,14 @@ +validate('cardReference'); + + $data['customer-vault-id'] = $this->getCardReference(); + + return $data; + } +} diff --git a/src/Message/ThreeStepRedirectVoidRequest.php b/src/Message/ThreeStepRedirectVoidRequest.php new file mode 100644 index 0000000..fad777b --- /dev/null +++ b/src/Message/ThreeStepRedirectVoidRequest.php @@ -0,0 +1,45 @@ +validate('transactionReference'); + + $data = array( + 'api-key' => $this->getApiKey(), + 'transaction-id' => $this->getTransactionReference(), + ); + + if ($this->getMerchantDefinedField_1()) { + $data['merchant-defined-field-1'] = $this->getMerchantDefinedField_1(); + } + + if ($this->getMerchantDefinedField_2()) { + $data['merchant-defined-field-2'] = $this->getMerchantDefinedField_2(); + } + + if ($this->getMerchantDefinedField_3()) { + $data['merchant-defined-field-3'] = $this->getMerchantDefinedField_3(); + } + + if ($this->getMerchantDefinedField_4()) { + $data['merchant-defined-field-4'] = $this->getMerchantDefinedField_4(); + } + + return $data; + } +} diff --git a/src/ThreeStepRedirectGateway.php b/src/ThreeStepRedirectGateway.php new file mode 100644 index 0000000..18bcccc --- /dev/null +++ b/src/ThreeStepRedirectGateway.php @@ -0,0 +1,171 @@ + '', + 'redirect_url' => '', + 'endpoint' => '', + ); + } + + /** + * @return string + */ + public function getApiKey() + { + return $this->getParameter('api_key'); + } + + /** + * @param string + * @return \Omnipay\Common\AbstractGateway + */ + public function setApiKey($value) + { + return $this->setParameter('api_key', $value); + } + + /** + * @return string + */ + public function getRedirectUrl() + { + return $this->getParameter('redirect_url'); + } + + /** + * @param string + * @return \Omnipay\Common\AbstractGateway + */ + public function setRedirectUrl($value) + { + return $this->setParameter('redirect_url', $value); + } + + /** + * Transaction sales are submitted and immediately flagged for settlement. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectSaleRequest + */ + public function sale(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectSaleRequest', $parameters); + } + + /** + * Transaction authorizations are authorized immediately but are not flagged + * for settlement. These transactions must be flagged for settlement using + * the capture transaction type. Authorizations typically remain active for + * three to seven business days. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectAuthRequest + */ + public function auth(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectAuthRequest', $parameters); + } + + /** + * Transaction captures flag existing authorizations for settlement. + * Only authorizations can be captured. Captures can be submitted for an + * amount equal to or less than the original authorization. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectCaptureRequest + */ + public function capture(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectCaptureRequest', $parameters); + } + + /** + * Transaction voids will cancel an existing sale or captured authorization. + * In addition, non-captured authorizations can be voided to prevent any + * future capture. Voids can only occur if the transaction has not been settled. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectVoidRequest + */ + public function void(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectVoidRequest', $parameters); + } + + /** + * Transaction refunds will reverse a previously settled transaction. If the + * transaction has not been settled, it must be voided instead of refunded. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectRefundRequest + */ + public function refund(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectRefundRequest', $parameters); + } + + /** + * Transaction credits apply an amount to the cardholder's card that was not + * originally processed through the Gateway. In most situations credits are + * disabled as transaction refunds should be used instead. + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectCreditRequest + */ + public function credit(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectCreditRequest', $parameters); + } + + /** + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectCreateCardRequest + */ + public function createCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectCreateCardRequest', $parameters); + } + + /** + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectUpdateCardRequest + */ + public function updateCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectUpdateCardRequest', $parameters); + } + + /** + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectDeleteCardRequest + */ + public function deleteCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectDeleteCardRequest', $parameters); + } + + /** + * @param array + * @return \Omnipay\NMI\Message\ThreeStepRedirectCompleteActionRequest + */ + public function completeAction(array $parameters = array()) + { + return $this->createRequest('\Omnipay\NMI\Message\ThreeStepRedirectCompleteActionRequest', $parameters); + } +}