Transaction.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. <?php
  2. namespace Braintree;
  3. /**
  4. * Braintree Transaction processor
  5. * Creates and manages transactions
  6. *
  7. * At minimum, an amount, credit card number, and
  8. * credit card expiration date are required.
  9. *
  10. * <b>Minimalistic example:</b>
  11. * <code>
  12. * Transaction::saleNoValidate(array(
  13. * 'amount' => '100.00',
  14. * 'creditCard' => array(
  15. * 'number' => '5105105105105100',
  16. * 'expirationDate' => '05/12',
  17. * ),
  18. * ));
  19. * </code>
  20. *
  21. * <b>Full example:</b>
  22. * <code>
  23. * Transaction::saleNoValidate(array(
  24. * 'amount' => '100.00',
  25. * 'orderId' => '123',
  26. * 'channel' => 'MyShoppingCardProvider',
  27. * 'creditCard' => array(
  28. * // if token is omitted, the gateway will generate a token
  29. * 'token' => 'credit_card_123',
  30. * 'number' => '5105105105105100',
  31. * 'expirationDate' => '05/2011',
  32. * 'cvv' => '123',
  33. * ),
  34. * 'customer' => array(
  35. * // if id is omitted, the gateway will generate an id
  36. * 'id' => 'customer_123',
  37. * 'firstName' => 'Dan',
  38. * 'lastName' => 'Smith',
  39. * 'company' => 'Braintree',
  40. * 'email' => 'dan@example.com',
  41. * 'phone' => '419-555-1234',
  42. * 'fax' => '419-555-1235',
  43. * 'website' => 'http://braintreepayments.com'
  44. * ),
  45. * 'billing' => array(
  46. * 'firstName' => 'Carl',
  47. * 'lastName' => 'Jones',
  48. * 'company' => 'Braintree',
  49. * 'streetAddress' => '123 E Main St',
  50. * 'extendedAddress' => 'Suite 403',
  51. * 'locality' => 'Chicago',
  52. * 'region' => 'IL',
  53. * 'postalCode' => '60622',
  54. * 'countryName' => 'United States of America'
  55. * ),
  56. * 'shipping' => array(
  57. * 'firstName' => 'Andrew',
  58. * 'lastName' => 'Mason',
  59. * 'company' => 'Braintree',
  60. * 'streetAddress' => '456 W Main St',
  61. * 'extendedAddress' => 'Apt 2F',
  62. * 'locality' => 'Bartlett',
  63. * 'region' => 'IL',
  64. * 'postalCode' => '60103',
  65. * 'countryName' => 'United States of America'
  66. * ),
  67. * 'customFields' => array(
  68. * 'birthdate' => '11/13/1954'
  69. * )
  70. * )
  71. * </code>
  72. *
  73. * <b>== Storing in the Vault ==</b>
  74. *
  75. * The customer and credit card information used for
  76. * a transaction can be stored in the vault by setting
  77. * <i>transaction[options][storeInVault]</i> to true.
  78. * <code>
  79. * $transaction = Transaction::saleNoValidate(array(
  80. * 'customer' => array(
  81. * 'firstName' => 'Adam',
  82. * 'lastName' => 'Williams'
  83. * ),
  84. * 'creditCard' => array(
  85. * 'number' => '5105105105105100',
  86. * 'expirationDate' => '05/2012'
  87. * ),
  88. * 'options' => array(
  89. * 'storeInVault' => true
  90. * )
  91. * ));
  92. *
  93. * echo $transaction->customerDetails->id
  94. * // '865534'
  95. * echo $transaction->creditCardDetails->token
  96. * // '6b6m'
  97. * </code>
  98. *
  99. * To also store the billing address in the vault, pass the
  100. * <b>addBillingAddressToPaymentMethod</b> option.
  101. * <code>
  102. * Transaction.saleNoValidate(array(
  103. * ...
  104. * 'options' => array(
  105. * 'storeInVault' => true
  106. * 'addBillingAddressToPaymentMethod' => true
  107. * )
  108. * ));
  109. * </code>
  110. *
  111. * <b>== Submitting for Settlement==</b>
  112. *
  113. * This can only be done when the transction's
  114. * status is <b>authorized</b>. If <b>amount</b> is not specified,
  115. * the full authorized amount will be settled. If you would like to settle
  116. * less than the full authorized amount, pass the desired amount.
  117. * You cannot settle more than the authorized amount.
  118. *
  119. * A transaction can be submitted for settlement when created by setting
  120. * $transaction[options][submitForSettlement] to true.
  121. *
  122. * <code>
  123. * $transaction = Transaction::saleNoValidate(array(
  124. * 'amount' => '100.00',
  125. * 'creditCard' => array(
  126. * 'number' => '5105105105105100',
  127. * 'expirationDate' => '05/2012'
  128. * ),
  129. * 'options' => array(
  130. * 'submitForSettlement' => true
  131. * )
  132. * ));
  133. * </code>
  134. *
  135. * <b>== More information ==</b>
  136. *
  137. * For more detailed information on Transactions, see {@link https://developers.braintreepayments.com/reference/response/transaction/php https://developers.braintreepayments.com/reference/response/transaction/php}
  138. *
  139. * @package Braintree
  140. * @category Resources
  141. *
  142. *
  143. * @property-read string $avsErrorResponseCode
  144. * @property-read string $avsPostalCodeResponseCode
  145. * @property-read string $avsStreetAddressResponseCode
  146. * @property-read string $cvvResponseCode
  147. * @property-read string $id transaction id
  148. * @property-read string $amount transaction amount
  149. * @property-read Braintree\Transaction\AddressDetails $billingDetails transaction billing address
  150. * @property-read \DateTime $createdAt transaction created DateTime
  151. * @property-read Braintree\ApplePayCardDetails $applePayCardDetails transaction Apple Pay card info
  152. * @property-read Braintree\AndroidPayCardDetails $androidPayCardDetails transaction Android Pay card info
  153. * @property-read Braintree\AmexExpressCheckoutCardDetails $amexExpressCheckoutCardDetails transaction Amex Express Checkout card info
  154. * @property-read Braintree\CreditCardDetails $creditCardDetails transaction credit card info
  155. * @property-read Braintree\CoinbaseDetails $coinbaseDetails transaction Coinbase account info
  156. * @property-read Braintree\MasterpassCardDetails $masterpassCardDetails transaction Masterpass card info
  157. * @property-read Braintree\PayPalDetails $paypalDetails transaction paypal account info
  158. * @property-read Braintree\SamsungPayCardDetails $samsungPayCardDetails transaction Samsung Pay card info
  159. * @property-read Braintree\Transaction\CustomerDetails $customerDetails transaction customer info
  160. * @property-read Braintree\VenmoAccount $venmoAccountDetails transaction Venmo Account info
  161. * @property-read Braintree\IdealPayment $idealPaymentDetails transaction Ideal Payment info
  162. * @property-read Braintree\VisaCheckoutCardDetails $visaCheckoutCardDetails transaction Visa Checkout card info
  163. * @property-read array $customFields custom fields passed with the request
  164. * @property-read string $processorResponseCode gateway response code
  165. * @property-read string $additionalProcessorResponse raw response from processor
  166. * @property-read Braintree\Transaction\AddressDetails $shippingDetails transaction shipping address
  167. * @property-read string $status transaction status
  168. * @property-read array $statusHistory array of StatusDetails objects
  169. * @property-read string $type transaction type
  170. * @property-read \DateTime $updatedAt transaction updated DateTime
  171. * @property-read Braintree\Disbursement $disbursementDetails populated when transaction is disbursed
  172. * @property-read Braintree\Dispute $disputes populated when transaction is disputed
  173. * @property-read Braintree\AuthorizationAdjustment $authorizationAdjustments populated when a transaction has authorization adjustments created when submitted for settlement
  174. *
  175. */
  176. class Transaction extends Base
  177. {
  178. // Transaction Status
  179. const AUTHORIZATION_EXPIRED = 'authorization_expired';
  180. const AUTHORIZING = 'authorizing';
  181. const AUTHORIZED = 'authorized';
  182. const GATEWAY_REJECTED = 'gateway_rejected';
  183. const FAILED = 'failed';
  184. const PROCESSOR_DECLINED = 'processor_declined';
  185. const SETTLED = 'settled';
  186. const SETTLING = 'settling';
  187. const SUBMITTED_FOR_SETTLEMENT = 'submitted_for_settlement';
  188. const VOIDED = 'voided';
  189. const UNRECOGNIZED = 'unrecognized';
  190. const SETTLEMENT_DECLINED = 'settlement_declined';
  191. const SETTLEMENT_PENDING = 'settlement_pending';
  192. const SETTLEMENT_CONFIRMED = 'settlement_confirmed';
  193. // Transaction Escrow Status
  194. const ESCROW_HOLD_PENDING = 'hold_pending';
  195. const ESCROW_HELD = 'held';
  196. const ESCROW_RELEASE_PENDING = 'release_pending';
  197. const ESCROW_RELEASED = 'released';
  198. const ESCROW_REFUNDED = 'refunded';
  199. // Transaction Types
  200. const SALE = 'sale';
  201. const CREDIT = 'credit';
  202. // Transaction Created Using
  203. const FULL_INFORMATION = 'full_information';
  204. const TOKEN = 'token';
  205. // Transaction Sources
  206. const API = 'api';
  207. const CONTROL_PANEL = 'control_panel';
  208. const RECURRING = 'recurring';
  209. // Gateway Rejection Reason
  210. const AVS = 'avs';
  211. const AVS_AND_CVV = 'avs_and_cvv';
  212. const CVV = 'cvv';
  213. const DUPLICATE = 'duplicate';
  214. const FRAUD = 'fraud';
  215. const THREE_D_SECURE = 'three_d_secure';
  216. const APPLICATION_INCOMPLETE = 'application_incomplete';
  217. // Industry Types
  218. const LODGING_INDUSTRY = 'lodging';
  219. const TRAVEL_AND_CRUISE_INDUSTRY = 'travel_cruise';
  220. /**
  221. * sets instance properties from an array of values
  222. *
  223. * @ignore
  224. * @access protected
  225. * @param array $transactionAttribs array of transaction data
  226. * @return void
  227. */
  228. protected function _initialize($transactionAttribs)
  229. {
  230. $this->_attributes = $transactionAttribs;
  231. if (isset($transactionAttribs['applePay'])) {
  232. $this->_set('applePayCardDetails',
  233. new Transaction\ApplePayCardDetails(
  234. $transactionAttribs['applePay']
  235. )
  236. );
  237. }
  238. if (isset($transactionAttribs['androidPayCard'])) {
  239. $this->_set('androidPayCardDetails',
  240. new Transaction\AndroidPayCardDetails(
  241. $transactionAttribs['androidPayCard']
  242. )
  243. );
  244. }
  245. if (isset($transactionAttribs['masterpassCard'])) {
  246. $this->_set('masterpassCardDetails',
  247. new Transaction\MasterpassCardDetails(
  248. $transactionAttribs['masterpassCard']
  249. )
  250. );
  251. }
  252. if (isset($transactionAttribs['visaCheckoutCard'])) {
  253. $this->_set('visaCheckoutCardDetails',
  254. new Transaction\VisaCheckoutCardDetails(
  255. $transactionAttribs['visaCheckoutCard']
  256. )
  257. );
  258. }
  259. if (isset($transactionAttribs['samsungPayCard'])) {
  260. $this->_set('samsungPayCardDetails',
  261. new Transaction\SamsungPayCardDetails(
  262. $transactionAttribs['samsungPayCard']
  263. )
  264. );
  265. }
  266. if (isset($transactionAttribs['amexExpressCheckoutCard'])) {
  267. $this->_set('amexExpressCheckoutCardDetails',
  268. new Transaction\AmexExpressCheckoutCardDetails(
  269. $transactionAttribs['amexExpressCheckoutCard']
  270. )
  271. );
  272. }
  273. if (isset($transactionAttribs['venmoAccount'])) {
  274. $this->_set('venmoAccountDetails',
  275. new Transaction\VenmoAccountDetails(
  276. $transactionAttribs['venmoAccount']
  277. )
  278. );
  279. }
  280. if (isset($transactionAttribs['creditCard'])) {
  281. $this->_set('creditCardDetails',
  282. new Transaction\CreditCardDetails(
  283. $transactionAttribs['creditCard']
  284. )
  285. );
  286. }
  287. if (isset($transactionAttribs['coinbaseAccount'])) {
  288. $this->_set('coinbaseDetails',
  289. new Transaction\CoinbaseDetails(
  290. $transactionAttribs['coinbaseAccount']
  291. )
  292. );
  293. }
  294. if (isset($transactionAttribs['usBankAccount'])) {
  295. $this->_set('usBankAccount',
  296. new Transaction\UsBankAccountDetails(
  297. $transactionAttribs['usBankAccount']
  298. )
  299. );
  300. }
  301. if (isset($transactionAttribs['idealPayment'])) {
  302. $this->_set('idealPayment',
  303. new Transaction\IdealPaymentDetails(
  304. $transactionAttribs['idealPayment']
  305. )
  306. );
  307. }
  308. if (isset($transactionAttribs['paypal'])) {
  309. $this->_set('paypalDetails',
  310. new Transaction\PayPalDetails(
  311. $transactionAttribs['paypal']
  312. )
  313. );
  314. }
  315. if (isset($transactionAttribs['customer'])) {
  316. $this->_set('customerDetails',
  317. new Transaction\CustomerDetails(
  318. $transactionAttribs['customer']
  319. )
  320. );
  321. }
  322. if (isset($transactionAttribs['billing'])) {
  323. $this->_set('billingDetails',
  324. new Transaction\AddressDetails(
  325. $transactionAttribs['billing']
  326. )
  327. );
  328. }
  329. if (isset($transactionAttribs['shipping'])) {
  330. $this->_set('shippingDetails',
  331. new Transaction\AddressDetails(
  332. $transactionAttribs['shipping']
  333. )
  334. );
  335. }
  336. if (isset($transactionAttribs['subscription'])) {
  337. $this->_set('subscriptionDetails',
  338. new Transaction\SubscriptionDetails(
  339. $transactionAttribs['subscription']
  340. )
  341. );
  342. }
  343. if (isset($transactionAttribs['descriptor'])) {
  344. $this->_set('descriptor',
  345. new Descriptor(
  346. $transactionAttribs['descriptor']
  347. )
  348. );
  349. }
  350. if (isset($transactionAttribs['disbursementDetails'])) {
  351. $this->_set('disbursementDetails',
  352. new DisbursementDetails($transactionAttribs['disbursementDetails'])
  353. );
  354. }
  355. $disputes = [];
  356. if (isset($transactionAttribs['disputes'])) {
  357. foreach ($transactionAttribs['disputes'] AS $dispute) {
  358. $disputes[] = Dispute::factory($dispute);
  359. }
  360. }
  361. $this->_set('disputes', $disputes);
  362. $statusHistory = [];
  363. if (isset($transactionAttribs['statusHistory'])) {
  364. foreach ($transactionAttribs['statusHistory'] AS $history) {
  365. $statusHistory[] = new Transaction\StatusDetails($history);
  366. }
  367. }
  368. $this->_set('statusHistory', $statusHistory);
  369. $addOnArray = [];
  370. if (isset($transactionAttribs['addOns'])) {
  371. foreach ($transactionAttribs['addOns'] AS $addOn) {
  372. $addOnArray[] = AddOn::factory($addOn);
  373. }
  374. }
  375. $this->_set('addOns', $addOnArray);
  376. $discountArray = [];
  377. if (isset($transactionAttribs['discounts'])) {
  378. foreach ($transactionAttribs['discounts'] AS $discount) {
  379. $discountArray[] = Discount::factory($discount);
  380. }
  381. }
  382. $this->_set('discounts', $discountArray);
  383. $authorizationAdjustments = [];
  384. if (isset($transactionAttribs['authorizationAdjustments'])) {
  385. foreach ($transactionAttribs['authorizationAdjustments'] AS $authorizationAdjustment) {
  386. $authorizationAdjustments[] = AuthorizationAdjustment::factory($authorizationAdjustment);
  387. }
  388. }
  389. $this->_set('authorizationAdjustments', $authorizationAdjustments);
  390. if(isset($transactionAttribs['riskData'])) {
  391. $this->_set('riskData', RiskData::factory($transactionAttribs['riskData']));
  392. }
  393. if(isset($transactionAttribs['threeDSecureInfo'])) {
  394. $this->_set('threeDSecureInfo', ThreeDSecureInfo::factory($transactionAttribs['threeDSecureInfo']));
  395. }
  396. if(isset($transactionAttribs['facilitatedDetails'])) {
  397. $this->_set('facilitatedDetails', FacilitatedDetails::factory($transactionAttribs['facilitatedDetails']));
  398. }
  399. if(isset($transactionAttribs['facilitatorDetails'])) {
  400. $this->_set('facilitatorDetails', FacilitatorDetails::factory($transactionAttribs['facilitatorDetails']));
  401. }
  402. }
  403. /**
  404. * returns a string representation of the transaction
  405. * @return string
  406. */
  407. public function __toString()
  408. {
  409. // array of attributes to print
  410. $display = [
  411. 'id', 'type', 'amount', 'status',
  412. 'createdAt', 'creditCardDetails', 'customerDetails'
  413. ];
  414. $displayAttributes = [];
  415. foreach ($display AS $attrib) {
  416. $displayAttributes[$attrib] = $this->$attrib;
  417. }
  418. return __CLASS__ . '[' .
  419. Util::attributesToString($displayAttributes) .']';
  420. }
  421. public function isEqual($otherTx)
  422. {
  423. return $this->id === $otherTx->id;
  424. }
  425. public function vaultCreditCard()
  426. {
  427. $token = $this->creditCardDetails->token;
  428. if (empty($token)) {
  429. return null;
  430. }
  431. else {
  432. return CreditCard::find($token);
  433. }
  434. }
  435. /** @return void|Braintree\Customer */
  436. public function vaultCustomer()
  437. {
  438. $customerId = $this->customerDetails->id;
  439. if (empty($customerId)) {
  440. return null;
  441. }
  442. else {
  443. return Customer::find($customerId);
  444. }
  445. }
  446. /** @return bool */
  447. public function isDisbursed() {
  448. return $this->disbursementDetails->isValid();
  449. }
  450. /** @return line items */
  451. public function lineItems() {
  452. return Configuration::gateway()->transactionLineItem()->findAll($this->id);
  453. }
  454. /**
  455. * factory method: returns an instance of Transaction
  456. * to the requesting method, with populated properties
  457. *
  458. * @ignore
  459. * @return Transaction
  460. */
  461. public static function factory($attributes)
  462. {
  463. $instance = new self();
  464. $instance->_initialize($attributes);
  465. return $instance;
  466. }
  467. // static methods redirecting to gateway
  468. public static function cloneTransaction($transactionId, $attribs)
  469. {
  470. return Configuration::gateway()->transaction()->cloneTransaction($transactionId, $attribs);
  471. }
  472. public static function createFromTransparentRedirect($queryString)
  473. {
  474. return Configuration::gateway()->transaction()->createFromTransparentRedirect($queryString);
  475. }
  476. public static function createTransactionUrl()
  477. {
  478. return Configuration::gateway()->transaction()->createTransactionUrl();
  479. }
  480. public static function credit($attribs)
  481. {
  482. return Configuration::gateway()->transaction()->credit($attribs);
  483. }
  484. public static function creditNoValidate($attribs)
  485. {
  486. return Configuration::gateway()->transaction()->creditNoValidate($attribs);
  487. }
  488. public static function find($id)
  489. {
  490. return Configuration::gateway()->transaction()->find($id);
  491. }
  492. public static function sale($attribs)
  493. {
  494. return Configuration::gateway()->transaction()->sale($attribs);
  495. }
  496. public static function saleNoValidate($attribs)
  497. {
  498. return Configuration::gateway()->transaction()->saleNoValidate($attribs);
  499. }
  500. public static function search($query)
  501. {
  502. return Configuration::gateway()->transaction()->search($query);
  503. }
  504. public static function fetch($query, $ids)
  505. {
  506. return Configuration::gateway()->transaction()->fetch($query, $ids);
  507. }
  508. public static function void($transactionId)
  509. {
  510. return Configuration::gateway()->transaction()->void($transactionId);
  511. }
  512. public static function voidNoValidate($transactionId)
  513. {
  514. return Configuration::gateway()->transaction()->voidNoValidate($transactionId);
  515. }
  516. public static function submitForSettlement($transactionId, $amount = null, $attribs = [])
  517. {
  518. return Configuration::gateway()->transaction()->submitForSettlement($transactionId, $amount, $attribs);
  519. }
  520. public static function submitForSettlementNoValidate($transactionId, $amount = null, $attribs = [])
  521. {
  522. return Configuration::gateway()->transaction()->submitForSettlementNoValidate($transactionId, $amount, $attribs);
  523. }
  524. public static function updateDetails($transactionId, $attribs = [])
  525. {
  526. return Configuration::gateway()->transaction()->updateDetails($transactionId, $attribs);
  527. }
  528. public static function submitForPartialSettlement($transactionId, $amount, $attribs = [])
  529. {
  530. return Configuration::gateway()->transaction()->submitForPartialSettlement($transactionId, $amount, $attribs);
  531. }
  532. public static function holdInEscrow($transactionId)
  533. {
  534. return Configuration::gateway()->transaction()->holdInEscrow($transactionId);
  535. }
  536. public static function releaseFromEscrow($transactionId)
  537. {
  538. return Configuration::gateway()->transaction()->releaseFromEscrow($transactionId);
  539. }
  540. public static function cancelRelease($transactionId)
  541. {
  542. return Configuration::gateway()->transaction()->cancelRelease($transactionId);
  543. }
  544. public static function refund($transactionId, $amount = null)
  545. {
  546. return Configuration::gateway()->transaction()->refund($transactionId, $amount);
  547. }
  548. }
  549. class_alias('Braintree\Transaction', 'Braintree_Transaction');