123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- <?php
- namespace Braintree;
- use InvalidArgumentException;
- /**
- * Braintree TransactionGateway processor
- * Creates and manages transactions
- *
- *
- * <b>== More information ==</b>
- *
- * For more detailed information on Transactions, see {@link https://developers.braintreepayments.com/reference/response/transaction/php https://developers.braintreepayments.com/reference/response/transaction/php}
- *
- * @package Braintree
- * @category Resources
- */
- class TransactionGateway
- {
- private $_gateway;
- private $_config;
- private $_http;
- public function __construct($gateway)
- {
- $this->_gateway = $gateway;
- $this->_config = $gateway->config;
- $this->_config->assertHasAccessTokenOrKeys();
- $this->_http = new Http($gateway->config);
- }
- public function cloneTransaction($transactionId, $attribs)
- {
- Util::verifyKeys(self::cloneSignature(), $attribs);
- return $this->_doCreate('/transactions/' . $transactionId . '/clone', ['transactionClone' => $attribs]);
- }
- /**
- * @ignore
- * @access private
- * @param array $attribs
- * @return Result\Successful|Result\Error
- */
- private function create($attribs)
- {
- Util::verifyKeys(self::createSignature(), $attribs);
- return $this->_doCreate('/transactions', ['transaction' => $attribs]);
- }
- /**
- * @ignore
- * @access private
- * @param array $attribs
- * @return object
- * @throws Exception\ValidationError
- */
- private function createNoValidate($attribs)
- {
- $result = $this->create($attribs);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- /**
- *
- * @deprecated since version 2.3.0
- * @access public
- * @param array $attribs
- * @return object
- */
- public function createFromTransparentRedirect($queryString)
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::confirm", E_USER_NOTICE);
- $params = TransparentRedirect::parseAndValidateQueryString(
- $queryString
- );
- return $this->_doCreate(
- '/transactions/all/confirm_transparent_redirect_request',
- ['id' => $params['id']]
- );
- }
- /**
- *
- * @deprecated since version 2.3.0
- * @access public
- * @param none
- * @return string
- */
- public function createTransactionUrl()
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::url", E_USER_NOTICE);
- return $this->_config->baseUrl() . $this->_config->merchantPath() .
- '/transactions/all/create_via_transparent_redirect_request';
- }
- public static function cloneSignature()
- {
- return ['amount', 'channel', ['options' => ['submitForSettlement']]];
- }
- /**
- * creates a full array signature of a valid gateway request
- * @return array gateway request signature format
- */
- public static function createSignature()
- {
- return [
- 'amount',
- 'billingAddressId',
- 'channel',
- 'customerId',
- 'deviceData',
- 'deviceSessionId',
- 'fraudMerchantId',
- 'merchantAccountId',
- 'orderId',
- 'paymentMethodNonce',
- 'paymentMethodToken',
- 'purchaseOrderNumber',
- 'recurring',
- 'serviceFeeAmount',
- 'sharedPaymentMethodToken',
- 'sharedPaymentMethodNonce',
- 'sharedCustomerId',
- 'sharedShippingAddressId',
- 'sharedBillingAddressId',
- 'shippingAddressId',
- 'taxAmount',
- 'taxExempt',
- 'threeDSecureToken',
- 'transactionSource',
- 'type',
- 'venmoSdkPaymentMethodCode',
- 'shippingAmount',
- 'discountAmount',
- 'shipsFromPostalCode',
- ['riskData' =>
- ['customerBrowser', 'customerIp', 'customer_browser', 'customer_ip']
- ],
- ['creditCard' =>
- ['token', 'cardholderName', 'cvv', 'expirationDate', 'expirationMonth', 'expirationYear', 'number'],
- ],
- ['customer' =>
- [
- 'id', 'company', 'email', 'fax', 'firstName',
- 'lastName', 'phone', 'website'],
- ],
- ['billing' =>
- [
- 'firstName', 'lastName', 'company', 'countryName',
- 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
- 'extendedAddress', 'locality', 'postalCode', 'region',
- 'streetAddress'],
- ],
- ['shipping' =>
- [
- 'firstName', 'lastName', 'company', 'countryName',
- 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
- 'extendedAddress', 'locality', 'postalCode', 'region',
- 'streetAddress'],
- ],
- ['threeDSecurePassThru' =>
- [
- 'eciFlag',
- 'cavv',
- 'xid'],
- ],
- ['options' =>
- [
- 'holdInEscrow',
- 'storeInVault',
- 'storeInVaultOnSuccess',
- 'submitForSettlement',
- 'addBillingAddressToPaymentMethod',
- 'venmoSdkSession',
- 'storeShippingAddressInVault',
- 'payeeId',
- 'payeeEmail',
- 'skipAdvancedFraudChecking',
- 'skipAvs',
- 'skipCvv',
- ['threeDSecure' =>
- ['required']
- ],
- # TODO: Snake case version included for backwards compatiblity. Remove in the next major version
- ['three_d_secure' =>
- ['required']
- ],
- ['paypal' =>
- [
- 'payeeId',
- 'payeeEmail',
- 'customField',
- 'description',
- ['supplementaryData' => ['_anyKey_']],
- ]
- ],
- ['amexRewards' =>
- [
- 'requestId',
- 'points',
- 'currencyAmount',
- 'currencyIsoCode'
- ]
- ],
- ['venmo' =>
- [
- # TODO: Snake case version included for backwards compatiblity. Remove in the next major version
- 'profile_id',
- 'profileId'
- ]
- ]
- ],
- ],
- ['customFields' => ['_anyKey_']],
- ['descriptor' => ['name', 'phone', 'url']],
- ['paypalAccount' => ['payeeId', 'payeeEmail']],
- # TODO: Snake case version included for backwards compatiblity. Remove in the next major version
- ['apple_pay_card' => ['number', 'cardholder_name', 'cryptogram', 'expiration_month', 'expiration_year', 'eci_indicator']],
- ['applePayCard' => ['number', 'cardholderName', 'cryptogram', 'expirationMonth', 'expirationYear', 'eciIndicator']],
- ['industry' =>
- ['industryType',
- ['data' =>
- [
- 'folioNumber',
- 'checkInDate',
- 'checkOutDate',
- 'travelPackage',
- 'departureDate',
- 'lodgingCheckInDate',
- 'lodgingCheckOutDate',
- 'lodgingName',
- 'roomRate'
- ]
- ]
- ]
- ],
- ['lineItems' => ['quantity', 'name', 'description', 'kind', 'unitAmount', 'unitTaxAmount', 'totalAmount', 'discountAmount', 'taxAmount', 'unitOfMeasure', 'productCode', 'commodityCode', 'url']],
- ];
- }
- public static function submitForSettlementSignature()
- {
- return ['orderId', ['descriptor' => ['name', 'phone', 'url']]];
- }
- public static function updateDetailsSignature()
- {
- return ['amount', 'orderId', ['descriptor' => ['name', 'phone', 'url']]];
- }
- public static function refundSignature()
- {
- return ['amount', 'orderId'];
- }
- /**
- *
- * @access public
- * @param array $attribs
- * @return Result\Successful|Result\Error
- */
- public function credit($attribs)
- {
- return $this->create(array_merge($attribs, ['type' => Transaction::CREDIT]));
- }
- /**
- *
- * @access public
- * @param array $attribs
- * @return Result\Successful|Result\Error
- * @throws Exception\ValidationError
- */
- public function creditNoValidate($attribs)
- {
- $result = $this->credit($attribs);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- /**
- * @access public
- * @param string id
- * @return Transaction
- */
- public function find($id)
- {
- $this->_validateId($id);
- try {
- $path = $this->_config->merchantPath() . '/transactions/' . $id;
- $response = $this->_http->get($path);
- return Transaction::factory($response['transaction']);
- } catch (Exception\NotFound $e) {
- throw new Exception\NotFound(
- 'transaction with id ' . $id . ' not found'
- );
- }
- }
- /**
- * new sale
- * @param array $attribs
- * @return Result\Successful|Result\Error
- */
- public function sale($attribs)
- {
- return $this->create(array_merge(['type' => Transaction::SALE], $attribs));
- }
- /**
- * roughly equivalent to the ruby bang method
- * @access public
- * @param array $attribs
- * @return array
- * @throws Exception\ValidationsFailed
- */
- public function saleNoValidate($attribs)
- {
- $result = $this->sale($attribs);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- /**
- * Returns a ResourceCollection of transactions matching the search query.
- *
- * If <b>query</b> is a string, the search will be a basic search.
- * If <b>query</b> is a hash, the search will be an advanced search.
- * For more detailed information and examples, see {@link https://developers.braintreepayments.com/reference/request/transaction/search/php https://developers.braintreepayments.com/reference/request/transaction/search/php}
- *
- * @param mixed $query search query
- * @param array $options options such as page number
- * @return ResourceCollection
- * @throws InvalidArgumentException
- */
- public function search($query)
- {
- $criteria = [];
- foreach ($query as $term) {
- $criteria[$term->name] = $term->toparam();
- }
- $path = $this->_config->merchantPath() . '/transactions/advanced_search_ids';
- $response = $this->_http->post($path, ['search' => $criteria]);
- if (array_key_exists('searchResults', $response)) {
- $pager = [
- 'object' => $this,
- 'method' => 'fetch',
- 'methodArgs' => [$query]
- ];
- return new ResourceCollection($response, $pager);
- } else {
- throw new Exception\DownForMaintenance();
- }
- }
- public function fetch($query, $ids)
- {
- $criteria = [];
- foreach ($query as $term) {
- $criteria[$term->name] = $term->toparam();
- }
- $criteria["ids"] = TransactionSearch::ids()->in($ids)->toparam();
- $path = $this->_config->merchantPath() . '/transactions/advanced_search';
- $response = $this->_http->post($path, ['search' => $criteria]);
- if (array_key_exists('creditCardTransactions', $response)) {
- return Util::extractattributeasarray(
- $response['creditCardTransactions'],
- 'transaction'
- );
- } else {
- throw new Exception\DownForMaintenance();
- }
- }
- /**
- * void a transaction by id
- *
- * @param string $id transaction id
- * @return Result\Successful|Result\Error
- */
- public function void($transactionId)
- {
- $this->_validateId($transactionId);
- $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/void';
- $response = $this->_http->put($path);
- return $this->_verifyGatewayResponse($response);
- }
- /**
- *
- */
- public function voidNoValidate($transactionId)
- {
- $result = $this->void($transactionId);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- public function submitForSettlement($transactionId, $amount = null, $attribs = [])
- {
- $this->_validateId($transactionId);
- Util::verifyKeys(self::submitForSettlementSignature(), $attribs);
- $attribs['amount'] = $amount;
- $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/submit_for_settlement';
- $response = $this->_http->put($path, ['transaction' => $attribs]);
- return $this->_verifyGatewayResponse($response);
- }
- public function submitForSettlementNoValidate($transactionId, $amount = null, $attribs = [])
- {
- $result = $this->submitForSettlement($transactionId, $amount, $attribs);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- public function updateDetails($transactionId, $attribs = [])
- {
- $this->_validateId($transactionId);
- Util::verifyKeys(self::updateDetailsSignature(), $attribs);
- $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/update_details';
- $response = $this->_http->put($path, ['transaction' => $attribs]);
- return $this->_verifyGatewayResponse($response);
- }
- public function submitForPartialSettlement($transactionId, $amount, $attribs = [])
- {
- $this->_validateId($transactionId);
- Util::verifyKeys(self::submitForSettlementSignature(), $attribs);
- $attribs['amount'] = $amount;
- $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/submit_for_partial_settlement';
- $response = $this->_http->post($path, ['transaction' => $attribs]);
- return $this->_verifyGatewayResponse($response);
- }
- public function holdInEscrow($transactionId)
- {
- $this->_validateId($transactionId);
- $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/hold_in_escrow';
- $response = $this->_http->put($path, []);
- return $this->_verifyGatewayResponse($response);
- }
- public function releaseFromEscrow($transactionId)
- {
- $this->_validateId($transactionId);
- $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/release_from_escrow';
- $response = $this->_http->put($path, []);
- return $this->_verifyGatewayResponse($response);
- }
- public function cancelRelease($transactionId)
- {
- $this->_validateId($transactionId);
- $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/cancel_release';
- $response = $this->_http->put($path, []);
- return $this->_verifyGatewayResponse($response);
- }
- public function refund($transactionId, $amount_or_options = null)
- {
- self::_validateId($transactionId);
- if(gettype($amount_or_options) == "array") {
- $options = $amount_or_options;
- } else {
- $options = [
- "amount" => $amount_or_options
- ];
- }
- Util::verifyKeys(self::refundSignature(), $options);
- $params = ['transaction' => $options];
- $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/refund';
- $response = $this->_http->post($path, $params);
- return $this->_verifyGatewayResponse($response);
- }
- /**
- * sends the create request to the gateway
- *
- * @ignore
- * @param var $subPath
- * @param array $params
- * @return Result\Successful|Result\Error
- */
- public function _doCreate($subPath, $params)
- {
- $fullPath = $this->_config->merchantPath() . $subPath;
- $response = $this->_http->post($fullPath, $params);
- return $this->_verifyGatewayResponse($response);
- }
- /**
- * verifies that a valid transaction id is being used
- * @ignore
- * @param string transaction id
- * @throws InvalidArgumentException
- */
- private function _validateId($id = null) {
- if (empty($id)) {
- throw new InvalidArgumentException(
- 'expected transaction id to be set'
- );
- }
- if (!preg_match('/^[0-9a-z]+$/', $id)) {
- throw new InvalidArgumentException(
- $id . ' is an invalid transaction id.'
- );
- }
- }
- /**
- * generic method for validating incoming gateway responses
- *
- * creates a new Transaction object and encapsulates
- * it inside a Result\Successful object, or
- * encapsulates a Errors object inside a Result\Error
- * alternatively, throws an Unexpected exception if the response is invalid.
- *
- * @ignore
- * @param array $response gateway response values
- * @return Result\Successful|Result\Error
- * @throws Exception\Unexpected
- */
- private function _verifyGatewayResponse($response)
- {
- if (isset($response['transaction'])) {
- // return a populated instance of Transaction
- return new Result\Successful(
- Transaction::factory($response['transaction'])
- );
- } else if (isset($response['apiErrorResponse'])) {
- return new Result\Error($response['apiErrorResponse']);
- } else {
- throw new Exception\Unexpected(
- "Expected transaction or apiErrorResponse"
- );
- }
- }
- }
- class_alias('Braintree\TransactionGateway', 'Braintree_TransactionGateway');
|