Gene_Braintree - Version 1.0.0

Version Notes

Connect your Magento store to Braintree to accept Credit Cards & PayPal using V.Zero SDK

Download this release

Release Info

Developer Dave Macaulay
Extension Gene_Braintree
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (184) hide show
  1. app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions.php +20 -0
  2. app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions/Grid.php +350 -0
  3. app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions/Search.php +110 -0
  4. app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Config.php +81 -0
  5. app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Currency.php +57 -0
  6. app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Moduleversion.php +95 -0
  7. app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Version.php +53 -0
  8. app/code/community/Gene/Braintree/Block/Cart/Totals.php +25 -0
  9. app/code/community/Gene/Braintree/Block/Creditcard.php +143 -0
  10. app/code/community/Gene/Braintree/Block/Creditcard/Info.php +127 -0
  11. app/code/community/Gene/Braintree/Block/Creditcard/Threedsecure.php +26 -0
  12. app/code/community/Gene/Braintree/Block/Js.php +138 -0
  13. app/code/community/Gene/Braintree/Block/Paypal.php +96 -0
  14. app/code/community/Gene/Braintree/Block/Paypal/Info.php +61 -0
  15. app/code/community/Gene/Braintree/Block/Saved.php +34 -0
  16. app/code/community/Gene/Braintree/Helper/Data.php +33 -0
  17. app/code/community/Gene/Braintree/Model/Debug.php +41 -0
  18. app/code/community/Gene/Braintree/Model/Observer.php +143 -0
  19. app/code/community/Gene/Braintree/Model/Paymentmethod/Abstract.php +75 -0
  20. app/code/community/Gene/Braintree/Model/Paymentmethod/Creditcard.php +380 -0
  21. app/code/community/Gene/Braintree/Model/Paymentmethod/Paypal.php +210 -0
  22. app/code/community/Gene/Braintree/Model/Saved.php +130 -0
  23. app/code/community/Gene/Braintree/Model/Source/Cctype.php +28 -0
  24. app/code/community/Gene/Braintree/Model/Source/Creditcard/CaptureAction.php +34 -0
  25. app/code/community/Gene/Braintree/Model/Source/Creditcard/PaymentAction.php +31 -0
  26. app/code/community/Gene/Braintree/Model/Source/Environment.php +28 -0
  27. app/code/community/Gene/Braintree/Model/Source/Paypal/Locale.php +55 -0
  28. app/code/community/Gene/Braintree/Model/Source/Paypal/Paymenttype.php +33 -0
  29. app/code/community/Gene/Braintree/Model/System/Config/Backend/Currency.php +32 -0
  30. app/code/community/Gene/Braintree/Model/Wrapper/Braintree.php +729 -0
  31. app/code/community/Gene/Braintree/controllers/Adminhtml/BraintreeController.php +97 -0
  32. app/code/community/Gene/Braintree/controllers/CheckoutController.php +61 -0
  33. app/code/community/Gene/Braintree/controllers/SavedController.php +92 -0
  34. app/code/community/Gene/Braintree/etc/adminhtml.xml +41 -0
  35. app/code/community/Gene/Braintree/etc/config.xml +191 -0
  36. app/code/community/Gene/Braintree/etc/system.xml +500 -0
  37. app/code/community/Gene/Braintree/sql/gene_braintree_setup/install-0.1.0.php +30 -0
  38. app/design/adminhtml/default/default/layout/gene/braintree.xml +25 -0
  39. app/design/adminhtml/default/default/template/gene/braintree/creditcard.phtml +135 -0
  40. app/design/adminhtml/default/default/template/gene/braintree/creditcard/info.phtml +17 -0
  41. app/design/adminhtml/default/default/template/gene/braintree/js.phtml +63 -0
  42. app/design/adminhtml/default/default/template/gene/braintree/paypal/info.phtml +17 -0
  43. app/design/adminhtml/default/default/template/gene/braintree/transactions/index.phtml +12 -0
  44. app/design/adminhtml/default/default/template/gene/braintree/transactions/search.phtml +101 -0
  45. app/design/frontend/base/default/layout/gene/braintree.xml +83 -0
  46. app/design/frontend/base/default/template/gene/braintree/creditcard.phtml +228 -0
  47. app/design/frontend/base/default/template/gene/braintree/creditcard/info.phtml +20 -0
  48. app/design/frontend/base/default/template/gene/braintree/creditcard/threedsecure.phtml +2 -0
  49. app/design/frontend/base/default/template/gene/braintree/customer/methods.phtml +23 -0
  50. app/design/frontend/base/default/template/gene/braintree/customer/saved.phtml +34 -0
  51. app/design/frontend/base/default/template/gene/braintree/js/amasty.phtml +375 -0
  52. app/design/frontend/base/default/template/gene/braintree/js/data.phtml +15 -0
  53. app/design/frontend/base/default/template/gene/braintree/js/default.phtml +188 -0
  54. app/design/frontend/base/default/template/gene/braintree/js/idev.phtml +402 -0
  55. app/design/frontend/base/default/template/gene/braintree/js/setup.phtml +36 -0
  56. app/design/frontend/base/default/template/gene/braintree/paypal.phtml +106 -0
  57. app/design/frontend/base/default/template/gene/braintree/paypal/info.phtml +21 -0
  58. app/etc/modules/Gene_Braintree.xml +9 -0
  59. app/locale/en_US/Gene_Braintree.csv +121 -0
  60. js/gene/braintree/braintree.js +5 -0
  61. js/gene/braintree/vzero.js +753 -0
  62. lib/Braintree.php +194 -0
  63. lib/Braintree/AddOn.php +18 -0
  64. lib/Braintree/AddOnGateway.php +27 -0
  65. lib/Braintree/Address.php +116 -0
  66. lib/Braintree/AddressGateway.php +286 -0
  67. lib/Braintree/ApplePayCard.php +95 -0
  68. lib/Braintree/ClientToken.php +29 -0
  69. lib/Braintree/ClientTokenGateway.php +90 -0
  70. lib/Braintree/CoinbaseAccount.php +108 -0
  71. lib/Braintree/Collection.php +153 -0
  72. lib/Braintree/Configuration.php +329 -0
  73. lib/Braintree/CreditCard.php +292 -0
  74. lib/Braintree/CreditCardGateway.php +471 -0
  75. lib/Braintree/CreditCardVerification.php +22 -0
  76. lib/Braintree/CreditCardVerificationGateway.php +48 -0
  77. lib/Braintree/CreditCardVerificationSearch.php +33 -0
  78. lib/Braintree/Customer.php +262 -0
  79. lib/Braintree/CustomerGateway.php +594 -0
  80. lib/Braintree/CustomerSearch.php +31 -0
  81. lib/Braintree/Descriptor.php +4 -0
  82. lib/Braintree/Digest.php +59 -0
  83. lib/Braintree/Disbursement.php +49 -0
  84. lib/Braintree/DisbursementDetails.php +25 -0
  85. lib/Braintree/Discount.php +18 -0
  86. lib/Braintree/DiscountGateway.php +27 -0
  87. lib/Braintree/Dispute.php +75 -0
  88. lib/Braintree/Dispute/TransactionDetails.php +22 -0
  89. lib/Braintree/EqualityNode.php +10 -0
  90. lib/Braintree/Error/Codes.php +457 -0
  91. lib/Braintree/Error/ErrorCollection.php +109 -0
  92. lib/Braintree/Error/Validation.php +56 -0
  93. lib/Braintree/Error/ValidationErrorCollection.php +127 -0
  94. lib/Braintree/Exception.php +11 -0
  95. lib/Braintree/Exception/Authentication.php +13 -0
  96. lib/Braintree/Exception/Authorization.php +15 -0
  97. lib/Braintree/Exception/Configuration.php +12 -0
  98. lib/Braintree/Exception/DownForMaintenance.php +12 -0
  99. lib/Braintree/Exception/ForgedQueryString.php +16 -0
  100. lib/Braintree/Exception/InvalidSignature.php +5 -0
  101. lib/Braintree/Exception/NotFound.php +12 -0
  102. lib/Braintree/Exception/SSLCaFileNotFound.php +12 -0
  103. lib/Braintree/Exception/SSLCertificate.php +12 -0
  104. lib/Braintree/Exception/ServerError.php +12 -0
  105. lib/Braintree/Exception/Unexpected.php +13 -0
  106. lib/Braintree/Exception/UpgradeRequired.php +12 -0
  107. lib/Braintree/Exception/ValidationsFailed.php +12 -0
  108. lib/Braintree/Gateway.php +101 -0
  109. lib/Braintree/Http.php +106 -0
  110. lib/Braintree/Instance.php +72 -0
  111. lib/Braintree/IsNode.php +21 -0
  112. lib/Braintree/KeyValueNode.php +22 -0
  113. lib/Braintree/MerchantAccount.php +62 -0
  114. lib/Braintree/MerchantAccount/AddressDetails.php +5 -0
  115. lib/Braintree/MerchantAccount/BusinessDetails.php +19 -0
  116. lib/Braintree/MerchantAccount/FundingDetails.php +6 -0
  117. lib/Braintree/MerchantAccount/IndividualDetails.php +19 -0
  118. lib/Braintree/MerchantAccountGateway.php +151 -0
  119. lib/Braintree/Modification.php +23 -0
  120. lib/Braintree/MultipleValueNode.php +37 -0
  121. lib/Braintree/MultipleValueOrTextNode.php +45 -0
  122. lib/Braintree/PartialMatchNode.php +16 -0
  123. lib/Braintree/PartnerMerchant.php +40 -0
  124. lib/Braintree/PayPalAccount.php +107 -0
  125. lib/Braintree/PayPalAccountGateway.php +174 -0
  126. lib/Braintree/PaymentInstrumentType.php +9 -0
  127. lib/Braintree/PaymentMethod.php +44 -0
  128. lib/Braintree/PaymentMethodGateway.php +251 -0
  129. lib/Braintree/PaymentMethodNonce.php +46 -0
  130. lib/Braintree/PaymentMethodNonceGateway.php +46 -0
  131. lib/Braintree/Plan.php +48 -0
  132. lib/Braintree/PlanGateway.php +30 -0
  133. lib/Braintree/RangeNode.php +38 -0
  134. lib/Braintree/ResourceCollection.php +141 -0
  135. lib/Braintree/Result/CreditCardVerification.php +84 -0
  136. lib/Braintree/Result/Error.php +109 -0
  137. lib/Braintree/Result/Successful.php +74 -0
  138. lib/Braintree/RiskData.php +27 -0
  139. lib/Braintree/SettlementBatchSummary.php +31 -0
  140. lib/Braintree/SettlementBatchSummaryGateway.php +66 -0
  141. lib/Braintree/SignatureService.php +22 -0
  142. lib/Braintree/Subscription.php +138 -0
  143. lib/Braintree/Subscription/StatusDetails.php +19 -0
  144. lib/Braintree/SubscriptionGateway.php +209 -0
  145. lib/Braintree/SubscriptionSearch.php +64 -0
  146. lib/Braintree/Test/CreditCardNumbers.php +69 -0
  147. lib/Braintree/Test/MerchantAccount.php +19 -0
  148. lib/Braintree/Test/Nonces.php +31 -0
  149. lib/Braintree/Test/TransactionAmounts.php +17 -0
  150. lib/Braintree/Test/VenmoSdk.php +28 -0
  151. lib/Braintree/TextNode.php +10 -0
  152. lib/Braintree/Transaction.php +504 -0
  153. lib/Braintree/Transaction/AddressDetails.php +24 -0
  154. lib/Braintree/Transaction/ApplePayCardDetails.php +36 -0
  155. lib/Braintree/Transaction/CoinbaseDetails.php +36 -0
  156. lib/Braintree/Transaction/CreditCardDetails.php +35 -0
  157. lib/Braintree/Transaction/CustomerDetails.php +22 -0
  158. lib/Braintree/Transaction/PayPalDetails.php +36 -0
  159. lib/Braintree/Transaction/StatusDetails.php +18 -0
  160. lib/Braintree/Transaction/SubscriptionDetails.php +15 -0
  161. lib/Braintree/TransactionGateway.php +444 -0
  162. lib/Braintree/TransactionSearch.php +131 -0
  163. lib/Braintree/TransparentRedirect.php +100 -0
  164. lib/Braintree/TransparentRedirectGateway.php +282 -0
  165. lib/Braintree/UnknownPaymentMethod.php +68 -0
  166. lib/Braintree/Util.php +332 -0
  167. lib/Braintree/Version.php +33 -0
  168. lib/Braintree/WebhookNotification.php +120 -0
  169. lib/Braintree/WebhookTesting.php +283 -0
  170. lib/Braintree/Xml.php +38 -0
  171. lib/Braintree/Xml/Generator.php +144 -0
  172. lib/Braintree/Xml/Parser.php +179 -0
  173. lib/ssl/api_braintreegateway_com.ca.crt +351 -0
  174. lib/ssl/sandbox_braintreegateway_com.ca.crt +20 -0
  175. package.xml +18 -0
  176. skin/frontend/base/default/images/gene/braintree/.DS_Store +0 -0
  177. skin/frontend/base/default/images/gene/braintree/AE.png +0 -0
  178. skin/frontend/base/default/images/gene/braintree/DI.png +0 -0
  179. skin/frontend/base/default/images/gene/braintree/JCB.png +0 -0
  180. skin/frontend/base/default/images/gene/braintree/MC.png +0 -0
  181. skin/frontend/base/default/images/gene/braintree/ME.png +0 -0
  182. skin/frontend/base/default/images/gene/braintree/PP.png +0 -0
  183. skin/frontend/base/default/images/gene/braintree/VI.png +0 -0
  184. skin/frontend/base/default/images/gene/braintree/card.png +0 -0
app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_Report_Transactions
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_Report_Transactions extends Mage_Adminhtml_Block_Widget_Grid_Container
9
+ {
10
+ public function __construct()
11
+ {
12
+ $this->_blockGroup = 'gene_braintree';
13
+ $this->_controller = 'adminhtml_report_transactions';
14
+ $this->_headerText = Mage::helper('gene_braintree')->__('Braintree Transactions');
15
+
16
+ parent::__construct();
17
+
18
+ $this->_removeButton('add');
19
+ }
20
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions/Grid.php ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_Report_Transactions_Grid
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_Report_Transactions_Grid extends Mage_Adminhtml_Block_Widget_Grid
9
+ {
10
+ /**
11
+ * We allow overriding of the search query
12
+ */
13
+ private $searchQuery = false;
14
+
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->setId('gene_braintree_settlement_grid');
19
+ $this->setDefaultSort('qty_ordered');
20
+ $this->setDefaultDir('DESC');
21
+
22
+ // As we're building a custom collection the standard filters won't work
23
+ $this->setPagerVisibility(false);
24
+ $this->setFilterVisibility(false);
25
+ }
26
+
27
+ /**
28
+ * Allow anyone invoking this grid to overriding the search query
29
+ *
30
+ * @param $query
31
+ */
32
+ public function setSearchQuery($query)
33
+ {
34
+ $this->searchQuery = $query;
35
+ }
36
+
37
+ /**
38
+ * Build up a search query based on the users entries
39
+ *
40
+ * @return $this
41
+ */
42
+ protected function _prepareBraintreeSearchQuery()
43
+ {
44
+ // Has the search query been set already?
45
+ if($this->searchQuery) {
46
+ return $this->searchQuery;
47
+ }
48
+
49
+ $searchArray = array();
50
+
51
+ // Init some times
52
+ $to = new Datetime();
53
+ $from = clone $to;
54
+ $from = $from->modify("-24 hour");
55
+
56
+ // If a from and to date are set modify things
57
+ if(Mage::app()->getRequest()->getParam('from_date') && Mage::app()->getRequest()->getParam('to_date')) {
58
+ $from = new DateTime(Mage::app()->getRequest()->getParam('from_date'));
59
+ $to = new DateTime(Mage::app()->getRequest()->getParam('to_date'));
60
+ }
61
+
62
+ // We always want to be filtering by a date to some degree
63
+ $searchArray[] = Braintree_TransactionSearch::createdAt()->between($from, $to);
64
+
65
+ // Type search
66
+ if($type = Mage::app()->getRequest()->getParam('type')) {
67
+ $searchArray[] = Braintree_TransactionSearch::type()->is($type);
68
+ }
69
+
70
+ // Allow searching upon the status
71
+ if($status = Mage::app()->getRequest()->getParam('status')) {
72
+ $searchArray[] = Braintree_TransactionSearch::status()->is($status);
73
+ }
74
+
75
+ // Order ID searching can be helpful
76
+ if($orderId = Mage::app()->getRequest()->getParam('order_id')) {
77
+ $searchArray[] = Braintree_TransactionSearch::orderId()->is($orderId);
78
+ }
79
+
80
+ // Store the search query within the session
81
+ Mage::getSingleton('adminhtml/session')->setBraintreeSearchQuery($searchArray);
82
+
83
+ return $searchArray;
84
+ }
85
+
86
+ /**
87
+ * Prepare the collection for the report
88
+ *
89
+ * @return $this|Mage_Adminhtml_Block_Widget_Grid
90
+ */
91
+ protected function _prepareCollection()
92
+ {
93
+ // Add in a new collection
94
+ $collection = new Varien_Data_Collection();
95
+
96
+ // Init the wrapper
97
+ $wrapper = Mage::getModel('gene_braintree/wrapper_braintree');
98
+
99
+ // Validate the credentials
100
+ if($wrapper->validateCredentials()) {
101
+
102
+ // Grab all transactions
103
+ $transactions = Braintree_Transaction::search($this->_prepareBraintreeSearchQuery());
104
+
105
+ // Retrieve the order IDs
106
+ $orderIds = array();
107
+ /* @var $transaction Braintree_Transaction */
108
+ foreach ($transactions as $transaction) {
109
+ $orderIds[] = $transaction->orderId;
110
+ }
111
+
112
+ // Retrieve all of the orders from a collection
113
+ $orders = Mage::getResourceModel('sales/order_collection')->addAttributeToFilter('increment_id', array('in' => $orderIds));
114
+
115
+ /* @var $transaction Braintree_Transaction */
116
+ foreach ($transactions as $transaction) {
117
+
118
+ // Create a new varien object
119
+ $transactionItem = new Varien_Object();
120
+ $transactionItem->setData((array)$transaction->_attributes);
121
+
122
+ // Grab the Magento order from the previously built collection
123
+ /* @var $magentoOrder Mage_Sales_Model_Order */
124
+ $magentoOrder = $orders->getItemByColumnValue('increment_id', $transaction->orderId);
125
+
126
+ // Set the Magento Order ID into the collection
127
+ // Not all transactions maybe coming from Magento
128
+ if ($magentoOrder && $magentoOrder->getId()) {
129
+ $transactionItem->setMagentoOrderId($magentoOrder->getId());
130
+ $transactionItem->setOrderStatus($magentoOrder->getStatus());
131
+ } else {
132
+ $transactionItem->setOrderStatus('<em>Unknown</em>');
133
+ }
134
+
135
+ // Add the item into the collection
136
+ $collection->addItem($transactionItem);
137
+ }
138
+
139
+ } else {
140
+
141
+ // If the Braintree details aren't valid take them to the configuration page
142
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('gene_braintree')->__('You must enter valid details into the Braintree v.zero - Configuration payment method before viewing transactions.'));
143
+
144
+ // Send the users on their way
145
+ Mage::app()->getResponse()->setRedirect(Mage::helper('adminhtml')->getUrl('/system_config/edit/section/payment') . '#payment_gene_braintree-head');
146
+ Mage::app()->getResponse()->sendResponse();
147
+
148
+ // Stop processing this method
149
+ return false;
150
+ }
151
+
152
+ $this->setCollection($collection);
153
+ parent::_prepareCollection();
154
+ return $this;
155
+ }
156
+
157
+ /**
158
+ * Prepare the columns we're wanting to display
159
+ *
160
+ * @return $this
161
+ *
162
+ * @throws Exception
163
+ */
164
+ protected function _prepareColumns()
165
+ {
166
+ $helper = Mage::helper('gene_braintree');
167
+
168
+ $this->addColumn('id', array(
169
+ 'header' => $helper->__('ID'),
170
+ 'index' => 'id',
171
+ 'width' => 120,
172
+ 'filter' => false,
173
+ 'sortable' => false
174
+ ));
175
+
176
+ $this->addColumn('created_at', array(
177
+ 'header' => $helper->__('Transaction Date'),
178
+ 'index' => 'created_at',
179
+ 'type' => 'datetime',
180
+ 'frame_callback' => array($this, 'handleDate'),
181
+ 'filter' => false,
182
+ 'sortable' => false
183
+ ));
184
+
185
+ $this->addColumn('orderId', array(
186
+ 'header' => $helper->__('Magento Order ID'),
187
+ 'index' => 'orderId',
188
+ 'width' => 120,
189
+ 'filter' => false,
190
+ 'sortable' => false
191
+ ));
192
+
193
+ $this->addColumn('order_status', array(
194
+ 'header' => $helper->__('Magento Status'),
195
+ 'index' => 'order_status',
196
+ 'type' => 'options',
197
+ 'options' => Mage::getSingleton('sales/order_config')->getStatuses(),
198
+ 'filter' => false,
199
+ 'sortable' => false
200
+ ));
201
+
202
+ $this->addColumn('merchantAccountId', array(
203
+ 'header' => $helper->__('Merchant Account ID'),
204
+ 'index' => 'merchantAccountId',
205
+ 'filter' => false,
206
+ 'sortable' => false
207
+ ));
208
+
209
+ $this->addColumn('type', array(
210
+ 'header' => $helper->__('Type'),
211
+ 'index' => 'type',
212
+ 'frame_callback' => array($this, 'handleType'),
213
+ 'filter' => false,
214
+ 'sortable' => false
215
+ ));
216
+
217
+ $this->addColumn('payment_information', array(
218
+ 'header' => $helper->__('Payment Information'),
219
+ 'index' => 'payment_information',
220
+ 'frame_callback' => array($this, 'handlePaymentInformation'),
221
+ 'filter' => false,
222
+ 'sortable' => false
223
+ ));
224
+
225
+ $this->addColumn('amount', array(
226
+ 'header' => $helper->__('Amount'),
227
+ 'index' => 'amount',
228
+ 'type' => 'number',
229
+ 'frame_callback' => array($this, 'handleAmount'),
230
+ 'filter' => false,
231
+ 'sortable' => false
232
+ ));
233
+
234
+ $this->addColumn('currencyIsoCode', array(
235
+ 'header' => $helper->__('Currency'),
236
+ 'index' => 'currencyIsoCode',
237
+ 'filter' => false,
238
+ 'sortable' => false
239
+ ));
240
+
241
+ $this->addColumn('status', array(
242
+ 'header' => $helper->__('Braintree Status'),
243
+ 'type' => 'options',
244
+ 'options' => $helper->getStatusesAsArray(),
245
+ 'index' => 'status',
246
+ 'filter' => false,
247
+ 'sortable' => false
248
+ ));
249
+
250
+ // Allow the admin to export this viewed data
251
+ $this->addExportType('*/*/exportCsv', $helper->__('CSV'));
252
+ $this->addExportType('*/*/exportExcel', $helper->__('Excel XML'));
253
+
254
+ return parent::_prepareColumns();
255
+ }
256
+
257
+ /**
258
+ * Format the amount into the currency of the transaction
259
+ *
260
+ * @param $value
261
+ * @param $row
262
+ * @param $column
263
+ * @param $isExport
264
+ *
265
+ * @return string
266
+ * @throws Zend_Currency_Exception
267
+ */
268
+ public function handleAmount($value, $row, $column, $isExport)
269
+ {
270
+ return Mage::app()->getLocale()->currency($row['currencyIsoCode'])->toCurrency($value);
271
+ }
272
+
273
+ /**
274
+ * Return the date object as a timestamp
275
+ *
276
+ * @param $value
277
+ * @param $row
278
+ * @param $column
279
+ * @param $isExport
280
+ *
281
+ * @return int
282
+ */
283
+ public function handleDate($value, $row, $column, $isExport)
284
+ {
285
+ /* @var $date DateTime */
286
+ $date = $row['createdAt'];
287
+
288
+ return $date->format('r');
289
+ }
290
+
291
+ /**
292
+ * Upper case the first letter of the type
293
+ *
294
+ * @param $value
295
+ * @param $row
296
+ * @param $column
297
+ * @param $isExport
298
+ *
299
+ * @return string
300
+ */
301
+ public function handleType($value, $row, $column, $isExport)
302
+ {
303
+ return ucfirst($value);
304
+ }
305
+
306
+ /**
307
+ * Display payment information regarding the transaction
308
+ *
309
+ * @param $value
310
+ * @param $row
311
+ * @param $column
312
+ * @param $isExport
313
+ *
314
+ * @return string
315
+ */
316
+ public function handlePaymentInformation($value, $row, $column, $isExport)
317
+ {
318
+ // Grab the image associated with this payment
319
+ $image = false;
320
+ if(!$isExport) {
321
+ $image = '<img height="26" align="left" src=' . (isset($row['paymentInstrumentType']) && $row['paymentInstrumentType'] == 'paypal_account' ? $row['paypal']['imageUrl'] : $row['creditCard']['imageUrl']) . '" />&nbsp;&nbsp;';
322
+ }
323
+
324
+ // Display the actual payment information
325
+ $response = false;
326
+ if(isset($row['paymentInstrumentType']) && $row['paymentInstrumentType'] == 'paypal_account') {
327
+ $response = $image . $row['paypal']['payerEmail'];
328
+ } else if(isset($row['paymentInstrumentType']) && $row['paymentInstrumentType'] == 'credit_card') {
329
+ $response = $image . $row['creditCard']['bin'] . '******' . $row['creditCard']['last4'];
330
+ }
331
+
332
+ return (!$isExport ? '<span style="line-height: 26px;">' : '') . $response . (!$isExport ? '</span>' : '');
333
+ }
334
+
335
+ /**
336
+ * If an item has a Magento Order ID take them to the sales order view screen
337
+ *
338
+ * @param $row
339
+ *
340
+ * @return string
341
+ */
342
+ public function getRowUrl($row)
343
+ {
344
+ if($row->getMagentoOrderId()) {
345
+ return $this->getUrl('*/sales_order/view', array('order_id' => $row->getMagentoOrderId()));
346
+ }
347
+ return false;
348
+ }
349
+
350
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/Report/Transactions/Search.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_Report_Transactions_Search
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_Report_Transactions_Search extends Mage_Core_Block_Template
9
+ {
10
+ /**
11
+ * Return the from date
12
+ *
13
+ * @return string
14
+ */
15
+ public function getFromDate()
16
+ {
17
+ if($fromDate = Mage::app()->getRequest()->getParam('from_date')) {
18
+ return $fromDate;
19
+ }
20
+
21
+ return $this->formateDateBraintree(strtotime('-24 hour'));
22
+ }
23
+
24
+ /**
25
+ * Return the to date
26
+ *
27
+ * @return string
28
+ */
29
+ public function getToDate()
30
+ {
31
+ if($toDate = Mage::app()->getRequest()->getParam('to_date')) {
32
+ return $toDate;
33
+ }
34
+
35
+ return $this->formateDateBraintree(time());
36
+ }
37
+
38
+ /**
39
+ * Return all of the possible statuses
40
+ *
41
+ * @return array
42
+ */
43
+ public function getStatusesAsArray()
44
+ {
45
+ // Add in a show all option
46
+ $all[''] = 'Show All';
47
+
48
+ // Grab all the statuses
49
+ $statuses = Mage::helper('gene_braintree')->getStatusesAsArray();
50
+
51
+ // Combine them
52
+ return array_merge($all, $statuses);
53
+ }
54
+
55
+ /**
56
+ * Return the types as an array
57
+ *
58
+ * @return array
59
+ */
60
+ public function getTypesAsArray()
61
+ {
62
+ return array(
63
+ '' => 'All',
64
+ 'sale' => 'Sale',
65
+ 'credit' => 'Credit'
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Return the selected status
71
+ *
72
+ * @return mixed
73
+ */
74
+ public function getSelectedType()
75
+ {
76
+ return Mage::app()->getRequest()->getParam('type');
77
+ }
78
+
79
+ /**
80
+ * Return the selected status
81
+ *
82
+ * @return mixed
83
+ */
84
+ public function getSelectedStatus()
85
+ {
86
+ return Mage::app()->getRequest()->getParam('status');
87
+ }
88
+
89
+ /**
90
+ * Return the selected status
91
+ *
92
+ * @return mixed
93
+ */
94
+ public function getOrderId()
95
+ {
96
+ return Mage::app()->getRequest()->getParam('order_id');
97
+ }
98
+
99
+ /**
100
+ * Format the date for display on the Braintree search form
101
+ *
102
+ * @param $date
103
+ *
104
+ * @return string
105
+ */
106
+ public function formateDateBraintree($date)
107
+ {
108
+ return date('d-m-Y G:i', $date);
109
+ }
110
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Config.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Config
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Config
9
+ extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface
10
+ {
11
+ /**
12
+ * Render element html
13
+ *
14
+ * @param Varien_Data_Form_Element_Abstract $element
15
+ * @return string
16
+ */
17
+ public function render(Varien_Data_Form_Element_Abstract $element)
18
+ {
19
+ $useContainerId = $element->getData('use_container_id');
20
+ return sprintf('<tr id="row_%s">
21
+ <td class="label">
22
+ <strong id="%s">%s</strong>
23
+ </td>
24
+ <td class="value">
25
+ %s
26
+ </td>
27
+ </tr>',
28
+ $element->getHtmlId(), $element->getHtmlId(), $element->getLabel(), $this->getValidConfigHtml()
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Inform the user there version will not work
34
+ * @return string
35
+ */
36
+ private function getValidConfigHtml()
37
+ {
38
+ $response = Mage::getModel('gene_braintree/wrapper_braintree')->validateCredentials(true);
39
+ $response.= '
40
+ <script type="text/javascript">
41
+
42
+ // Set the config timeout
43
+ var configTimeout;
44
+
45
+ // Make a request to the server and validate the configuration options
46
+ function checkConfig() {
47
+
48
+ // Clear any timeout already set
49
+ clearTimeout(configTimeout);
50
+
51
+ // Defined the configTimeout
52
+ configTimeout = setTimeout(function() {
53
+ // Make the request
54
+ new Ajax.Request(
55
+ "' . Mage::helper('adminhtml')->getUrl('adminhtml/braintree/validateConfig') . '",
56
+ {
57
+ method: "post",
58
+ onSuccess: function(transport){
59
+ $(\'row_payment_gene_braintree_valid_config\').down(\'td.value\').innerHTML = transport.responseText;
60
+ },
61
+ parameters: Form.serializeElements($$(\'.validate-config\'))
62
+ }
63
+ );
64
+ }, 800);
65
+ }
66
+
67
+ // Observe the relevant form elements
68
+ $$(\'input.validate-config\').each(function(element) {
69
+ Event.observe(element, \'keyup\', function() {
70
+ checkConfig();
71
+ });
72
+ });
73
+ $$(\'select.validate-config\').each(function(element) {
74
+ Event.observe(element, \'change\', function() {
75
+ checkConfig();
76
+ });
77
+ });
78
+ </script>';
79
+ return $response;
80
+ }
81
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Currency.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Currency
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Currency
9
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
10
+ {
11
+ /**
12
+ * Enter description here...
13
+ *
14
+ * @param Varien_Data_Form_Element_Abstract $element
15
+ * @return string
16
+ */
17
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
18
+ {
19
+ return $this->getCurrencyTableHtml($element);
20
+ }
21
+
22
+ /**
23
+ * Inform the user there version will not work
24
+ * @return string
25
+ */
26
+ private function getCurrencyTableHtml(Varien_Data_Form_Element_Abstract $element)
27
+ {
28
+ // Store ID = scope ID
29
+ $storeId = Mage::getSingleton('adminhtml/config_data')->getScopeId();
30
+
31
+ // Retrieve the currencies
32
+ $currencies = Mage::app()->getStore($storeId)->getAvailableCurrencyCodes();
33
+
34
+ // Retrieve the values
35
+ $values = $element->getValue();
36
+
37
+ // Build our response
38
+ $response = '<input type="hidden" id="payment_gene_braintree_multi_currency_mapping" />
39
+ <table width="100%" cellspacing="6" cellpadding="4">
40
+ <tr>
41
+ <th width="35%">' . $this->__('Currency Code') . '</th>
42
+ <th width="65%">' . $this->__('Merchant Account ID') . '</th>
43
+ </tr>';
44
+
45
+ // Loop through each currency and add a value
46
+ foreach($currencies as $currency) {
47
+ $response .= '<tr>
48
+ <td> ' . $currency . '</td>
49
+ <td><input class="input-text" type="text" name=" ' . $element->getName() . '[' . $currency . ']" style="width: 100%;" value="'. (isset($values->$currency) ? $values->$currency : '') . '" /></td>
50
+ </tr>';
51
+ }
52
+
53
+ $response .= '</table>';
54
+
55
+ return $response;
56
+ }
57
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Moduleversion.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Moduleversion
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Moduleversion
9
+ extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface
10
+ {
11
+ /**
12
+ * Render element html
13
+ *
14
+ * @param Varien_Data_Form_Element_Abstract $element
15
+ * @return string
16
+ */
17
+ public function render(Varien_Data_Form_Element_Abstract $element)
18
+ {
19
+ $useContainerId = $element->getData('use_container_id');
20
+ return sprintf('<tr id="row_%s">
21
+ <td class="label">
22
+ <strong id="%s">%s</strong>
23
+ </td>
24
+ <td class="value">
25
+ <span id="module-version">%s</span>
26
+ <div id="recent-version">
27
+ <div style="padding: 8px 0;line-height: 16px;">
28
+ <img src="' . $this->getSkinUrl('images/rule-ajax-loader.gif') . '" align="left" style="margin-right: 3px;" /> ' . $this->__('Checking latest version...') . '
29
+ </div>
30
+ </div>
31
+ </td>
32
+ </tr>',
33
+ $element->getHtmlId(), $element->getHtmlId(), $element->getLabel(), $this->getVersionHtml()
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Inform the user there version will not work
39
+ * @return string
40
+ */
41
+ private function getVersionHtml()
42
+ {
43
+ $response = Mage::getConfig()->getModuleConfig('Gene_Braintree')->version;
44
+ $response.= '
45
+ <script type="text/javascript">
46
+
47
+ // Define the module version in the window
48
+ var moduleVersion = \'' . Mage::getConfig()->getModuleConfig('Gene_Braintree')->version . '\';
49
+
50
+ // Once the dom has loaded make the checkout
51
+ document.observe("dom:loaded", function() {
52
+ try {
53
+ new Ajax.Request("//braintree.gene.co.uk/", {
54
+ method: "post", parameters: {version: moduleVersion},
55
+ onCreate: function(response) {
56
+ var t = response.transport;
57
+ t.setRequestHeader = t.setRequestHeader.wrap(function(original, k, v) {
58
+ if (/^(accept|accept-language|content-language)$/i.test(k))
59
+ return original(k, v);
60
+ if (/^content-type$/i.test(k) &&
61
+ /^(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)(;.+)?$/i.test(v))
62
+ return original(k, v);
63
+ return;
64
+ });
65
+ },
66
+ onSuccess: function(transport) {
67
+ try {
68
+ json = eval(\'(\' + transport.responseText + \')\');
69
+ } catch(e){}
70
+
71
+ // Is there a message to be displayed to the user?
72
+ if(json.message) {
73
+ $(\'recent-version\').innerHTML = json.message;
74
+ }
75
+
76
+ if(json.latest == true) {
77
+ $(\'module-version\').setStyle({color: \'green\'});
78
+ } else {
79
+ $(\'module-version\').setStyle({color: \'darkred\'});
80
+ }
81
+ },
82
+ onFailure: function() {
83
+ $(\'recent-version\').innerHTML = \'<span style="color:darkred;">Unable to check for updates</span>\';
84
+ }
85
+ });
86
+ } catch(e) {
87
+ $(\'recent-version\').innerHTML = \'<span style="color:darkred;">Unable to check for updates</span>\';
88
+ }
89
+ });
90
+ </script>
91
+ ';
92
+
93
+ return $response;
94
+ }
95
+ }
app/code/community/Gene/Braintree/Block/Adminhtml/System/Config/Braintree/Version.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Version
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Adminhtml_System_Config_Braintree_Version
9
+ extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface
10
+ {
11
+ /**
12
+ * Render element html
13
+ *
14
+ * @param Varien_Data_Form_Element_Abstract $element
15
+ * @return string
16
+ */
17
+ public function render(Varien_Data_Form_Element_Abstract $element)
18
+ {
19
+ $useContainerId = $element->getData('use_container_id');
20
+ return sprintf('<tr id="row_%s">
21
+ <td class="label">
22
+ <strong id="%s">%s</strong>
23
+ </td>
24
+ <td class="value">
25
+ %s
26
+ </td>
27
+ </tr>',
28
+ $element->getHtmlId(), $element->getHtmlId(), $element->getLabel(), $this->getVersionHtml()
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Inform the user there version will not work
34
+ * @return string
35
+ */
36
+ private function getVersionHtml()
37
+ {
38
+ if(@class_exists('Braintree_Version')) {
39
+ $version = Braintree_Version::get();
40
+ if ($version < 2.32) {
41
+ return '
42
+ <span style="color: red;">' . $version . '</span><br />
43
+ <small>
44
+ <strong>Warning:</strong> Our payment methods will not work with a version of the Braintree lib files older than 2.32.0. You\'ll have to upgrade, please download the newer version <a href="https://developers.braintreepayments.com/javascript+php/sdk/server/setup">here</a>. Once you\'ve downloaded it please replace the file <strong>/lib/Braintree.php</strong> and the folder <strong>/lib/Braintree/</strong> with the newer versions within the archive.
45
+ </small>';
46
+ } else {
47
+ return '<span style="color: green;">' . $version . '</span>';
48
+ }
49
+ } else {
50
+ return '<span style="color: red;font-weight: bold;">Not Installed</span>';
51
+ }
52
+ }
53
+ }
app/code/community/Gene/Braintree/Block/Cart/Totals.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Cart_Totals
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Cart_Totals extends Mage_Checkout_Block_Cart_Totals
9
+ {
10
+
11
+ /**
12
+ * Check if we have display grand total in base currency
13
+ *
14
+ * @return bool
15
+ */
16
+ public function needDisplayBaseGrandtotal()
17
+ {
18
+ // If we have a mapped currency code never display base grand total
19
+ if(Mage::getSingleton('gene_braintree/wrapper_braintree')->hasMappedCurrencyCode()) {
20
+ return false;
21
+ }
22
+
23
+ return parent::needDisplayBaseGrandtotal();
24
+ }
25
+ }
app/code/community/Gene/Braintree/Block/Creditcard.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Creditcard
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Creditcard extends Mage_Payment_Block_Form_Cc
9
+ {
10
+ /**
11
+ * Store our saved details
12
+ */
13
+ private $_savedDetails = false;
14
+
15
+ /**
16
+ * Set the template
17
+ */
18
+ protected function _construct()
19
+ {
20
+ parent::_construct();
21
+ $this->setTemplate('gene/braintree/creditcard.phtml');
22
+ }
23
+
24
+ /**
25
+ * Can we save the card?
26
+ *
27
+ * @return bool
28
+ */
29
+ protected function canSaveCard()
30
+ {
31
+ // Validate that the vault is enabled and that the user is either logged in or registering
32
+ if ($this->getMethod()->isVaultEnabled()
33
+ && (Mage::getSingleton('customer/session')->isLoggedIn()
34
+ || Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER))
35
+ {
36
+ return true;
37
+ }
38
+
39
+ return false;
40
+ }
41
+
42
+ /**
43
+ * is 3D secure enabled?
44
+ *
45
+ * @return mixed
46
+ */
47
+ protected function is3DEnabled()
48
+ {
49
+ return Mage::getModel('gene_braintree/paymentmethod_creditcard')->is3DEnabled();
50
+ }
51
+
52
+ /**
53
+ * Does this customer have saved accounts?
54
+ *
55
+ * @return mixed
56
+ */
57
+ public function hasSavedDetails()
58
+ {
59
+ if(Mage::getSingleton('customer/session')->isLoggedIn()) {
60
+ if ($this->getSavedDetails()) {
61
+ return sizeof($this->getSavedDetails());
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Return the saved accounts
69
+ *
70
+ * @return array
71
+ */
72
+ public function getSavedDetails()
73
+ {
74
+ if(!$this->_savedDetails) {
75
+ $this->_savedDetails = Mage::getSingleton('gene_braintree/saved')->getSavedMethodsByType(Gene_Braintree_Model_Saved::SAVED_CREDITCARD_ID);
76
+ }
77
+ return $this->_savedDetails;
78
+ }
79
+
80
+ /**
81
+ * Return the original CC types
82
+ *
83
+ * @return array
84
+ */
85
+ public function getOriginalCcAvailableTypes()
86
+ {
87
+ return parent::getCcAvailableTypes();
88
+ }
89
+
90
+ /**
91
+ * Convert the available types into something
92
+ *
93
+ * @return string
94
+ */
95
+ public function getCcAvailableTypes()
96
+ {
97
+ // Collect the types from the core method
98
+ $types = parent::getCcAvailableTypes();
99
+
100
+ // Grab the keys and encode
101
+ return json_encode(array_keys($types));
102
+ }
103
+
104
+ /**
105
+ * Return the card icon
106
+ *
107
+ * @param $cardType
108
+ *
109
+ * @return string
110
+ */
111
+ static public function getCardIcon($cardType)
112
+ {
113
+ // Convert the card type to lower case, no spaces
114
+ switch(str_replace(' ', '', strtolower($cardType))) {
115
+ case 'mastercard':
116
+ return 'MC.png';
117
+ break;
118
+ case 'visa':
119
+ return 'VI.png';
120
+ break;
121
+ case 'americanexpress':
122
+ case 'amex':
123
+ return 'AE.png';
124
+ break;
125
+ case 'discover':
126
+ return 'DI.png';
127
+ break;
128
+ case 'jcb':
129
+ return 'JCB.png';
130
+ break;
131
+ case 'maestro':
132
+ return 'ME.png';
133
+ break;
134
+ case 'paypal':
135
+ return 'PP.png';
136
+ break;
137
+ }
138
+
139
+ // Otherwise return the standard card image
140
+ return 'card.png';
141
+ }
142
+
143
+ }
app/code/community/Gene/Braintree/Block/Creditcard/Info.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Creditcard_Info
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Creditcard_Info extends Mage_Payment_Block_Info
9
+ {
10
+
11
+ /**
12
+ * Use a custom template
13
+ */
14
+ protected function _construct()
15
+ {
16
+ parent::_construct();
17
+ $this->setTemplate('gene/braintree/creditcard/info.phtml');
18
+ }
19
+
20
+ /**
21
+ * Return the currently viewed order
22
+ *
23
+ * @return \Mage_Sales_Model_Order
24
+ */
25
+ protected function getOrder()
26
+ {
27
+ if(Mage::registry('current_order')) {
28
+ return Mage::registry('current_order');
29
+ } else if(Mage::registry('current_invoice')) {
30
+ return Mage::registry('current_invoice')->getOrder();
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Prepare information specific to current payment method
36
+ *
37
+ * @param null | array $transport
38
+ *
39
+ * @return Varien_Object
40
+ */
41
+ protected function _prepareSpecificInformation($transport = null)
42
+ {
43
+ // Get the original transport data
44
+ $transport = parent::_prepareSpecificInformation($transport);
45
+
46
+ // Build up the data we wish to pass through
47
+ $data = array(
48
+ $this->__('Card Number (Last 4)') => $this->getInfo()->getCcLast4(),
49
+ $this->__('Credit Card Type') => $this->getInfo()->getCcType()
50
+ );
51
+
52
+ // Check we're in the admin area
53
+ if(Mage::app()->getStore()->isAdmin()) {
54
+
55
+ // Transaction ID won't matter for customers
56
+ $data[$this->__('Braintree Transaction ID')] = $this->getInfo()->getLastTransId();
57
+
58
+ // Add in the current status
59
+ try {
60
+ $transaction = Mage::getModel('gene_braintree/wrapper_braintree')->init($this->getOrder()->getStoreId())->findTransaction($this->getInfo()->getLastTransId());
61
+ if ($transaction) {
62
+ $data[$this->__('Status')] = $this->convertStatus($transaction->status);
63
+ } else {
64
+ $data[$this->__('Status')] = $this->__('<span style="color:red;"><strong>Warning:</strong> Cannot load payment in Braintree.</span>');
65
+ }
66
+ } catch (Exception $e) {
67
+ $data[$this->__('Status')] = $this->__('<span style="color:red;"><strong>Warning:</strong> Unable to connect to Braintree to load transaction.</span>');
68
+ }
69
+
70
+ // What additional information should we show
71
+ $additionalInfoHeadings = array(
72
+ 'avsErrorResponseCode' => $this->__('AVS Error Response Code'),
73
+ 'avsPostalCodeResponseCode' => $this->__('AVS Postal Response Code'),
74
+ 'avsStreetAddressResponseCode' => $this->__('AVS Street Address Response Code'),
75
+ 'cvvResponseCode' => $this->__('CVV Response Code'),
76
+ 'gatewayRejectionReason' => $this->__('Gateway Rejection Reason'),
77
+ 'processorAuthorizationCode' => $this->__('Processor Autorization Code'),
78
+ 'processorResponseCode' => $this->__('Processor Response Code'),
79
+ 'processorResponseText' => $this->__('Processor Response Text'),
80
+ 'threeDSecure' => $this->__('3D Secure')
81
+ );
82
+
83
+ // Add any of the data that we've recorded into the view
84
+ foreach($additionalInfoHeadings as $key => $heading) {
85
+ if($infoData = $this->getInfo()->getAdditionalInformation($key)) {
86
+ $data[$heading] = $infoData;
87
+ }
88
+ }
89
+
90
+ }
91
+
92
+ // Add the data to the class variable
93
+ $transport->setData(array_merge($data, $transport->getData()));
94
+ $this->_paymentSpecificInformation = $transport->getData();
95
+
96
+ // And return it
97
+ return $transport;
98
+ }
99
+
100
+ /**
101
+ * Make the status nicer to read
102
+ *
103
+ * @param $status
104
+ *
105
+ * @return string
106
+ */
107
+ private function convertStatus($status)
108
+ {
109
+ switch($status){
110
+ case 'authorized':
111
+ return '<span style="color: #40A500;"> ' . Mage::helper('gene_braintree')->__('Authorized') . '</span>';
112
+ break;
113
+ case 'submitted_for_settlement':
114
+ return '<span style="color: #40A500;">' . Mage::helper('gene_braintree')->__('Submitted For Settlement') . '</span>';
115
+ break;
116
+ case 'settled':
117
+ return '<span style="color: #40A500;">' . Mage::helper('gene_braintree')->__('Settled') . '</span>';
118
+ break;
119
+ case 'voided':
120
+ return '<span style="color: #ed4737;">' . Mage::helper('gene_braintree')->__('Voided') . '</span>';
121
+ break;
122
+ }
123
+
124
+ return ucwords($status);
125
+ }
126
+
127
+ }
app/code/community/Gene/Braintree/Block/Creditcard/Threedsecure.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Creditcard_Threedsecure
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Creditcard_Threedsecure extends Mage_Core_Block_Template
9
+ {
10
+ /**
11
+ * Only render if the payment method is active and 3D secure is enabled
12
+ *
13
+ * @return string
14
+ */
15
+ protected function _toHtml()
16
+ {
17
+ // Check the payment method is active
18
+ if (Mage::getModel('gene_braintree/paymentmethod_creditcard')->isAvailable()
19
+ && Mage::getModel('gene_braintree/paymentmethod_creditcard')->is3DEnabled()
20
+ ) {
21
+ return parent::_toHtml();
22
+ }
23
+
24
+ return '';
25
+ }
26
+ }
app/code/community/Gene/Braintree/Block/Js.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Js
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Js extends Mage_Core_Block_Template
9
+ {
10
+ /**
11
+ * We can use the same token twice
12
+ * @var bool
13
+ */
14
+ private $token = false;
15
+
16
+ /**
17
+ * Log whether methods are active
18
+ *
19
+ * @var bool
20
+ */
21
+ private $creditCardActive = null;
22
+ private $payPalActive = null;
23
+
24
+ /**
25
+ * Return whether PayPal is active
26
+ *
27
+ * @return bool|null
28
+ */
29
+ protected function isCreditCardActive()
30
+ {
31
+ if(is_null($this->creditCardActive)) {
32
+ $this->creditCardActive = Mage::getModel('gene_braintree/paymentmethod_creditcard')->isAvailable();
33
+ }
34
+
35
+ return $this->creditCardActive;
36
+ }
37
+
38
+ /**
39
+ * Return whether PayPal is active
40
+ *
41
+ * @return bool|null
42
+ */
43
+ protected function isPayPalActive()
44
+ {
45
+ if(is_null($this->payPalActive)) {
46
+ $this->payPalActive = Mage::getModel('gene_braintree/paymentmethod_paypal')->isAvailable();
47
+ }
48
+
49
+ return $this->payPalActive;
50
+ }
51
+
52
+ /**
53
+ * is 3D secure enabled?
54
+ *
55
+ * @return int
56
+ */
57
+ protected function is3DEnabled()
58
+ {
59
+ // Return an int
60
+ if(Mage::getModel('gene_braintree/paymentmethod_creditcard')->is3DEnabled()) {
61
+ return 1;
62
+ } else {
63
+ return 0;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Generate and return a token
69
+ *
70
+ * @return mixed
71
+ */
72
+ protected function getClientToken()
73
+ {
74
+ if(!$this->token) {
75
+ $this->token = Mage::getSingleton('gene_braintree/wrapper_braintree')->init()->generateToken();
76
+ }
77
+ return $this->token;
78
+ }
79
+
80
+ /**
81
+ * Shall we do a single use payment?
82
+ *
83
+ * @return string
84
+ */
85
+ protected function getSingleUse()
86
+ {
87
+ // We prefer to do future payments, so anything else is future
88
+ $paymentAction = Mage::getStoreConfig('payment/gene_braintree_paypal/payment_type');
89
+ if($paymentAction == Gene_Braintree_Model_Source_Paypal_Paymenttype::GENE_BRAINTREE_PAYPAL_SINGLE_PAYMENT) {
90
+ return 'true';
91
+ }
92
+
93
+ return 'false';
94
+ }
95
+
96
+ /**
97
+ * If we're using future payments should we retrieve a token or just do a singular payment?
98
+ *
99
+ * @return string
100
+ */
101
+ protected function getSingleFutureUse()
102
+ {
103
+ // We prefer to do future payments, so anything else is future
104
+ $paymentAction = Mage::getStoreConfig('payment/gene_braintree_paypal/payment_type');
105
+ if($paymentAction == Gene_Braintree_Model_Source_Paypal_Paymenttype::GENE_BRAINTREE_PAYPAL_FUTURE_PAYMENTS
106
+ && !Mage::getModel('gene_braintree/paymentmethod_paypal')->isVaultEnabled()) {
107
+ return 'true';
108
+ }
109
+
110
+ return 'false';
111
+ }
112
+
113
+ /**
114
+ * Return the locale for PayPal
115
+ *
116
+ * @return mixed
117
+ */
118
+ protected function getLocale()
119
+ {
120
+ return Mage::getStoreConfig('payment/gene_braintree_paypal/locale');
121
+ }
122
+
123
+ /**
124
+ * Only render if the payment method is active
125
+ *
126
+ * @return string
127
+ */
128
+ protected function _toHtml()
129
+ {
130
+ // Check the payment method is active
131
+ if($this->isCreditCardActive() || $this->isPayPalActive()) {
132
+ return parent::_toHtml();
133
+ }
134
+
135
+ return '';
136
+ }
137
+
138
+ }
app/code/community/Gene/Braintree/Block/Paypal.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Form
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Paypal extends Mage_Payment_Block_Form
9
+ {
10
+
11
+ /**
12
+ * Store this so we don't load it multiple times
13
+ */
14
+ private $_savedDetails = false;
15
+
16
+ /**
17
+ * Internal constructor. Set template
18
+ */
19
+ protected function _construct()
20
+ {
21
+ parent::_construct();
22
+ $this->setTemplate('gene/braintree/paypal.phtml');
23
+ }
24
+
25
+ /**
26
+ * Generate and return a token
27
+ *
28
+ * @return mixed
29
+ */
30
+ public function getClientToken()
31
+ {
32
+ return Mage::getModel('gene_braintree/wrapper_braintree')->init()->generateToken();
33
+ }
34
+
35
+ /**
36
+ * Shall we do a single use payment?
37
+ *
38
+ * @return string
39
+ */
40
+ public function getSingleUse()
41
+ {
42
+ // We prefer to do future payments, so anything else is future
43
+ $paymentAction = Mage::getStoreConfig('payment/gene_braintree_paypal/payment_type');
44
+ if($paymentAction == Gene_Braintree_Model_Source_Paypal_Paymenttype::GENE_BRAINTREE_PAYPAL_SINGLE_PAYMENT) {
45
+ return 'true';
46
+ }
47
+
48
+ return 'false';
49
+ }
50
+
51
+ /**
52
+ * Does this customer have saved accounts?
53
+ *
54
+ * @return mixed
55
+ */
56
+ public function hasSavedDetails()
57
+ {
58
+ if(Mage::getSingleton('customer/session')->isLoggedIn()) {
59
+ if($this->getSavedDetails()) {
60
+ return sizeof($this->getSavedDetails());
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Return the saved accounts
68
+ *
69
+ * @return bool
70
+ */
71
+ public function getSavedDetails()
72
+ {
73
+ if(!$this->_savedDetails) {
74
+ $this->_savedDetails = Mage::getSingleton('gene_braintree/saved')->getSavedMethodsByType(Gene_Braintree_Model_Saved::SAVED_PAYPAL_ID);
75
+ }
76
+ return $this->_savedDetails;
77
+ }
78
+
79
+ /**
80
+ * Is the vault enabled? Meaning we can save PayPal
81
+ *
82
+ * @return mixed
83
+ */
84
+ public function canSavePayPal()
85
+ {
86
+ if ($this->getMethod()->isVaultEnabled()
87
+ && (Mage::getSingleton('customer/session')->isLoggedIn()
88
+ || Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER))
89
+ {
90
+ return true;
91
+ }
92
+
93
+ return false;
94
+ }
95
+
96
+ }
app/code/community/Gene/Braintree/Block/Paypal/Info.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Info
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Paypal_Info extends Mage_Payment_Block_Info
9
+ {
10
+
11
+ /**
12
+ * Use a custom template
13
+ */
14
+ protected function _construct()
15
+ {
16
+ parent::_construct();
17
+ $this->setTemplate('gene/braintree/paypal/info.phtml');
18
+ }
19
+
20
+ /**
21
+ * Prepare information specific to current payment method
22
+ *
23
+ * @param null | array $transport
24
+ *
25
+ * @return Varien_Object
26
+ */
27
+ protected function _prepareSpecificInformation($transport = null)
28
+ {
29
+ // Get the original transport data
30
+ $transport = parent::_prepareSpecificInformation($transport);
31
+
32
+ // Build up the data we wish to pass through
33
+ $data = array(
34
+ $this->__('PayPal Email') => $this->getInfo()->getAdditionalInformation('paypal_email')
35
+ );
36
+
37
+ // Check we're in the admin area
38
+ if(Mage::app()->getStore()->isAdmin()) {
39
+
40
+ // Show these details to the admin only
41
+ $data = array_merge(
42
+ $data, array(
43
+ $this->__('Braintree Transaction ID') => $this->getInfo()->getLastTransId(),
44
+ $this->__('Payment ID') => $this->getInfo()->getAdditionalInformation('payment_id'),
45
+ $this->__('Authorization ID') => $this->getInfo()->getAdditionalInformation(
46
+ 'authorization_id'
47
+ )
48
+ )
49
+ );
50
+
51
+ }
52
+
53
+ // Add the data to the class variable
54
+ $transport->setData(array_merge($data, $transport->getData()));
55
+ $this->_paymentSpecificInformation = $transport->getData();
56
+
57
+ // And return it
58
+ return $transport;
59
+ }
60
+
61
+ }
app/code/community/Gene/Braintree/Block/Saved.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Block_Saved
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Block_Saved extends Mage_Core_Block_Template
9
+ {
10
+ /**
11
+ * Return whether the customer has saved details
12
+ *
13
+ * @param bool $type
14
+ *
15
+ * @return bool
16
+ */
17
+ public function hasSavedDetails($type = false)
18
+ {
19
+ return Mage::getSingleton('gene_braintree/saved')->hasType($type);
20
+ }
21
+
22
+ /**
23
+ * Retrieve those said saved details
24
+ *
25
+ * @param bool $type
26
+ *
27
+ * @return array
28
+ */
29
+ public function getSavedDetails($type = false)
30
+ {
31
+ return Mage::getSingleton('gene_braintree/saved')->getSavedMethodsByType($type);
32
+ }
33
+
34
+ }
app/code/community/Gene/Braintree/Helper/Data.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Helper_Data
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Helper_Data extends Mage_Core_Helper_Abstract
9
+ {
10
+ /**
11
+ * Return all of the possible statuses as an array
12
+ *
13
+ * @return array
14
+ */
15
+ public function getStatusesAsArray()
16
+ {
17
+ return array(
18
+ Braintree_Transaction::AUTHORIZATION_EXPIRED => $this->__('Authorization Expired'),
19
+ Braintree_Transaction::AUTHORIZING => $this->__('Authorizing'),
20
+ Braintree_Transaction::AUTHORIZED => $this->__('Authorized'),
21
+ Braintree_Transaction::GATEWAY_REJECTED => $this->__('Gateway Rejected'),
22
+ Braintree_Transaction::FAILED => $this->__('Failed'),
23
+ Braintree_Transaction::PROCESSOR_DECLINED => $this->__('Processor Declined'),
24
+ Braintree_Transaction::SETTLED => $this->__('Settled'),
25
+ Braintree_Transaction::SETTLING => $this->__('Settling'),
26
+ Braintree_Transaction::SUBMITTED_FOR_SETTLEMENT => $this->__('Submitted For Settlement'),
27
+ Braintree_Transaction::VOIDED => $this->__('Voided'),
28
+ Braintree_Transaction::UNRECOGNIZED => $this->__('Unrecognized'),
29
+ Braintree_Transaction::SETTLEMENT_DECLINED => $this->__('Settlement Declined'),
30
+ Braintree_Transaction::SETTLEMENT_PENDING => $this->__('Settlement Pending')
31
+ );
32
+ }
33
+ }
app/code/community/Gene/Braintree/Model/Debug.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Debug
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Debug extends Mage_Core_Model_Abstract
9
+ {
10
+
11
+ /**
12
+ * Is the debugging enabled?
13
+ */
14
+ const GENE_BRAINTREE_DEBUG = 'payment/gene_braintree/debug';
15
+
16
+ /**
17
+ * Where shall we store the debugging information
18
+ */
19
+ const GENE_BRAINTREE_DEBUG_FILE = 'gene_braintree.log';
20
+
21
+ /**
22
+ * Log any data passed to this method in the debug file
23
+ *
24
+ * @param $data
25
+ */
26
+ static public function log($data)
27
+ {
28
+ // Check the debug flag in the admin
29
+ if(Mage::getStoreConfigFlag(self::GENE_BRAINTREE_DEBUG)) {
30
+
31
+ // If the data is an exception convert it to a string
32
+ if($data instanceof Exception) {
33
+ $data = $data->getMessage() . $data->getTraceAsString();
34
+ }
35
+
36
+ // Use the built in logging function
37
+ Mage::log($data, null, self::GENE_BRAINTREE_DEBUG_FILE, true);
38
+ }
39
+ }
40
+
41
+ }
app/code/community/Gene/Braintree/Model/Observer.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Observer
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Observer
9
+ {
10
+
11
+ /**
12
+ * Detect which checkout is in use and add a new layout handle
13
+ *
14
+ * @param Varien_Event_Observer $observer
15
+ *
16
+ * @return $this
17
+ */
18
+ public function addLayoutHandle(Varien_Event_Observer $observer)
19
+ {
20
+ /* @var $action Mage_Core_Controller_Varien_Action */
21
+ $action = $observer->getAction();
22
+
23
+ /* @var $layout Mage_Core_Model_Layout */
24
+ $layout = $observer->getLayout();
25
+
26
+ // We only want to run this action on the checkout
27
+ if($action->getFullActionName() == 'checkout_onepage_index') {
28
+
29
+ // Attempt to detect Amasty_Scheckout
30
+ if (Mage::helper('core')->isModuleEnabled('Amasty_Scheckout')) {
31
+ $layout->getUpdate()->addHandle('amasty_onestep_checkout');
32
+ }
33
+
34
+ }
35
+
36
+ return $this;
37
+ }
38
+
39
+ /**
40
+ * Store the customer ID if set in session
41
+ *
42
+ * @param Varien_Event_Observer $observer
43
+ */
44
+ public function completeCheckout(Varien_Event_Observer $observer)
45
+ {
46
+ // Do we have a customer ID within the session?
47
+ if(Mage::getSingleton('checkout/session')->getBraintreeCustomerId() &&
48
+ Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == Mage_Checkout_Model_Type_Onepage::METHOD_CUSTOMER) {
49
+
50
+ // Get the customer
51
+ $customer = Mage::getSingleton('customer/session')->getCustomer();
52
+
53
+ // Save the braintree customer ID
54
+ $customer->setBraintreeCustomerId(Mage::getSingleton('checkout/session')->getBraintreeCustomerId())->save();
55
+ }
56
+
57
+ // Unset the ID from the session
58
+ Mage::getSingleton('checkout/session')->unsetData('braintree_customer_id');
59
+
60
+ return $this;
61
+ }
62
+
63
+ /**
64
+ * Capture payment on shipment if set
65
+ *
66
+ * @param Varien_Event_Observer $observer
67
+ *
68
+ * @return $this
69
+ */
70
+ public function captureBraintreePayment(Varien_Event_Observer $observer)
71
+ {
72
+ /* @var $shipment Mage_Sales_Model_Order_Shipment */
73
+ $shipment = $observer->getEvent()->getShipment();
74
+
75
+ /* @var $order Mage_Sales_Model_Order */
76
+ $order = $shipment->getOrder();
77
+
78
+ // Should we capture the payment in shipment?
79
+ if($this->shouldCaptureShipment($order)) {
80
+
81
+ // Check the order can be invoiced
82
+ if($order->canInvoice()) {
83
+
84
+ /* @var @invoice Mage_Sales_Model_Order_Invoice */
85
+ $invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
86
+
87
+ // Check the invoice has items to invoice
88
+ if ($invoice->getTotalQty()) {
89
+
90
+ // Set the requested capture case
91
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
92
+
93
+ // Register the invoice
94
+ $invoice->register();
95
+
96
+ // Save the transaction
97
+ $transactionSave = Mage::getModel('core/resource_transaction')
98
+ ->addObject($invoice)
99
+ ->addObject($invoice->getOrder());
100
+
101
+ // Save the transaction
102
+ $transactionSave->save();
103
+
104
+ }
105
+
106
+ }
107
+
108
+ }
109
+
110
+ return $this;
111
+ }
112
+
113
+ /**
114
+ * Store the currency mapping as a JSON string
115
+ *
116
+ * @param \Varien_Event_Observer $observer
117
+ *
118
+ * @return $this
119
+ */
120
+ public function modifyCurrencyMapping(Varien_Event_Observer $observer)
121
+ {
122
+
123
+ return $this;
124
+ }
125
+
126
+ /**
127
+ * Should we capture the payment?
128
+ *
129
+ * @param $order Mage_Sales_Model_Order
130
+ *
131
+ * @return bool
132
+ */
133
+ private function shouldCaptureShipment($order)
134
+ {
135
+ // Check the store configuration settings are set to capture shipment
136
+ if(Mage::getStoreConfig(Gene_Braintree_Model_Source_Creditcard_PaymentAction::PAYMENT_ACTION_XML_PATH, $order->getStoreId()) == Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE
137
+ && Mage::getStoreConfig(Gene_Braintree_Model_Source_Creditcard_CaptureAction::CAPTURE_ACTION_XML_PATH, $order->getStoreId()) == Gene_Braintree_Model_Source_Creditcard_CaptureAction::CAPTURE_SHIPMENT)
138
+ {
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ }
app/code/community/Gene/Braintree/Model/Paymentmethod/Abstract.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Paymentmethod_Abstract
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ abstract class Gene_Braintree_Model_Paymentmethod_Abstract extends Mage_Payment_Model_Method_Abstract
9
+ {
10
+
11
+ /**
12
+ * Verify that the module has been setup
13
+ *
14
+ * @param null $quote
15
+ *
16
+ * @return bool
17
+ */
18
+ public function isAvailable($quote = null)
19
+ {
20
+ // Check Magento's internal methods allow us to run
21
+ if(parent::isAvailable($quote)) {
22
+
23
+ // Validate the configuration is okay
24
+ return $this->_getWrapper()->validateCredentialsOnce();
25
+
26
+ } else {
27
+
28
+ // Otherwise it's a no
29
+ return false;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Return the helper
35
+ *
36
+ * @return Mage_Payment_Helper_Data
37
+ */
38
+ protected function _getHelper()
39
+ {
40
+ return Mage::helper('gene_braintree');
41
+ }
42
+
43
+ /**
44
+ * Return the wrapper class
45
+ *
46
+ * @return Gene_Braintree_Model_Wrapper_Braintree
47
+ */
48
+ protected function _getWrapper()
49
+ {
50
+ return Mage::getSingleton('gene_braintree/wrapper_braintree');
51
+ }
52
+
53
+ /**
54
+ * Return configuration values
55
+ *
56
+ * @param $value
57
+ *
58
+ * @return mixed
59
+ */
60
+ protected function _getConfig($key)
61
+ {
62
+ return Mage::getStoreConfig('payment/'.$this->_code.'/'.$key);
63
+ }
64
+
65
+ /**
66
+ * Is the vault enabled?
67
+ *
68
+ * @return bool
69
+ */
70
+ public function isVaultEnabled()
71
+ {
72
+ return $this->_getConfig('use_vault');
73
+ }
74
+
75
+ }
app/code/community/Gene/Braintree/Model/Paymentmethod/Creditcard.php ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Paymentmethod_Creditcard
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Paymentmethod_Creditcard extends Gene_Braintree_Model_Paymentmethod_Abstract
9
+ {
10
+ /**
11
+ * Setup block types
12
+ *
13
+ * @var string
14
+ */
15
+ protected $_formBlockType = 'gene_braintree/creditcard';
16
+ protected $_infoBlockType = 'gene_braintree/creditcard_info';
17
+
18
+ /**
19
+ * Set the code
20
+ *
21
+ * @var string
22
+ */
23
+ protected $_code = 'gene_braintree_creditcard';
24
+
25
+ /**
26
+ * Payment Method features
27
+ *
28
+ * @var bool
29
+ */
30
+ protected $_isGateway = false;
31
+ protected $_canOrder = false;
32
+ protected $_canAuthorize = true;
33
+ protected $_canCapture = true;
34
+ protected $_canCapturePartial = true;
35
+ protected $_canRefund = false;
36
+ protected $_canRefundInvoicePartial = false;
37
+ protected $_canVoid = false;
38
+ protected $_canUseInternal = true;
39
+ protected $_canUseCheckout = true;
40
+ protected $_canUseForMultishipping = false;
41
+ protected $_isInitializeNeeded = false;
42
+ protected $_canFetchTransactionInfo = false;
43
+ protected $_canReviewPayment = false;
44
+ protected $_canCreateBillingAgreement = false;
45
+ protected $_canManageRecurringProfiles = false;
46
+
47
+ /**
48
+ * If we're trying to charge a 3D secure card in the vault we need to build a special nonce
49
+ *
50
+ * @param $paymentMethodToken
51
+ *
52
+ * @return mixed
53
+ */
54
+ public function getThreeDSecureVaultNonce($paymentMethodToken)
55
+ {
56
+ return $this->_getWrapper()->getThreeDSecureVaultNonce($paymentMethodToken);
57
+ }
58
+
59
+ /**
60
+ * Is 3D secure enabled?
61
+ *
62
+ * @return bool
63
+ */
64
+ public function is3DEnabled()
65
+ {
66
+ // 3D secure can never be enabled for the admin
67
+ if(Mage::app()->getStore()->isAdmin()) {
68
+ return false;
69
+ }
70
+
71
+ if($this->_getConfig('threedsecure')) {
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+
77
+ /**
78
+ * Do we need to send the CCV, which Braintree calls a CVV?
79
+ *
80
+ * @return mixed
81
+ */
82
+ public function requireCcv()
83
+ {
84
+ if($this->_getConfig('useccv')) {
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Psuedo _authorize function so we can pass in extra data
92
+ * @param Varien_Object $payment
93
+ * @param $amount
94
+ * @param bool $shouldCapture
95
+ *
96
+ * @throws Mage_Core_Exception
97
+ */
98
+ protected function _authorize(Varien_Object $payment, $amount, $shouldCapture = false)
99
+ {
100
+ // Retrieve the post data from the request
101
+ $paymentPost = Mage::app()->getRequest()->getPost('payment');
102
+
103
+ // Confirm that we have a nonce from Braintree
104
+ if(!isset($paymentPost['card_payment_method_token']) || (isset($paymentPost['card_payment_method_token']) && $paymentPost['card_payment_method_token'] == 'threedsecure')) {
105
+ if ((!isset($paymentPost['payment_method_nonce']) || empty($paymentPost['payment_method_nonce']))) {
106
+ Mage::throwException(
107
+ $this->_getHelper()->__('Your card payment has failed, please try again.')
108
+ );
109
+ }
110
+ } else if(isset($paymentPost['card_payment_method_token']) && empty($paymentPost['card_payment_method_token'])) {
111
+ Mage::throwException(
112
+ $this->_getHelper()->__('Your card payment has failed, please try again.')
113
+ );
114
+ }
115
+
116
+ // Get the device data for fraud screening
117
+ $deviceData = Mage::app()->getRequest()->getPost('device_data');
118
+
119
+ // Init the environment
120
+ $this->_getWrapper()->init();
121
+
122
+ // Attempt to create the sale
123
+ try {
124
+
125
+ // Pass over the CVV/CCV
126
+ if($this->requireCcv() && isset($paymentPost['cc_cid'])) {
127
+
128
+ $paymentArray['cvv'] = $paymentPost['cc_cid'];
129
+
130
+ } else if($this->requireCcv() && !isset($paymentPost['cc_cid']) && empty($paymentPost['card_payment_method_token'])) {
131
+
132
+ // Log it
133
+ Gene_Braintree_Model_Debug::log('CVV required but not present in request');
134
+
135
+ // Politely inform the user
136
+ Mage::throwException(
137
+ $this->_getHelper()->__('We require a CVV when creating card transactions.')
138
+ );
139
+
140
+ }
141
+
142
+ // Check to see whether we're using a payment method token?
143
+ if(isset($paymentPost['card_payment_method_token']) && !empty($paymentPost['card_payment_method_token']) && !in_array($paymentPost['card_payment_method_token'], array('other', 'threedsecure'))) {
144
+
145
+ // Build our payment array
146
+ $paymentArray = array(
147
+ 'paymentMethodToken' => $paymentPost['card_payment_method_token'],
148
+ );
149
+
150
+ unset($paymentArray['cvv']);
151
+
152
+ } else {
153
+
154
+ // Build our payment array with a nonce
155
+ $paymentArray = array(
156
+ 'paymentMethodNonce' => $paymentPost['payment_method_nonce']
157
+ );
158
+
159
+ }
160
+
161
+ // The 3D secure variable
162
+ $threeDSecure = $this->is3DEnabled();
163
+
164
+ // If the user is using a stored card with 3D secure, enable it in the request and remove CVV
165
+ if(isset($paymentPost['card_payment_method_token']) && $paymentPost['card_payment_method_token'] == 'threedsecure') {
166
+
167
+ // If we're using 3D secure token card don't send CVV
168
+ unset($paymentArray['cvv']);
169
+
170
+ // Force 3D secure on
171
+ $threeDSecure = true;
172
+
173
+ } elseif(isset($paymentPost['card_payment_method_token']) && !empty($paymentPost['card_payment_method_token']) && $paymentPost['card_payment_method_token'] != 'other') {
174
+
175
+ // Force 3D secure off
176
+ $threeDSecure = false;
177
+ }
178
+
179
+ // Retrieve the amount we should capture
180
+ $amount = $this->_getWrapper()->getCaptureAmount($payment->getOrder(), $amount);
181
+
182
+ // Build up the sale array
183
+ $saleArray = $this->_getWrapper()->buildSale(
184
+ $amount,
185
+ $paymentArray,
186
+ $payment->getOrder(),
187
+ $shouldCapture,
188
+ $deviceData,
189
+ ($this->isVaultEnabled() && isset($paymentPost['save_card']) && $paymentPost['save_card'] == 1),
190
+ $threeDSecure
191
+ );
192
+
193
+ // Pass the sale array into a varien object
194
+ $request = new Varien_Object();
195
+ $request->setData('sale_array', $saleArray);
196
+
197
+ // Dispatch event for modifying the sale array
198
+ Mage::dispatchEvent('gene_braintree_creditcard_sale_array', array('payment' => $payment, 'request' => $request));
199
+
200
+ // Pull the saleArray back out
201
+ $saleArray = $request->getData('sale_array');
202
+
203
+ // Log the initial sale array, no protected data is included
204
+ Gene_Braintree_Model_Debug::log(array('_authorize:saleArray' => $saleArray));
205
+
206
+ // Attempt to create the sale
207
+ $result = $this->_getWrapper()->makeSale(
208
+ $saleArray
209
+ );
210
+
211
+ } catch (Exception $e) {
212
+
213
+ // Dispatch an event for when a payment fails
214
+ Mage::dispatchEvent('gene_braintree_creditcard_failed_exception', array('payment' => $payment, 'exception' => $e));
215
+
216
+ // If there's an error
217
+ Gene_Braintree_Model_Debug::log($e);
218
+
219
+ Mage::throwException(
220
+ $this->_getHelper()->__('There was an issue whilst trying to process your card payment, please try again or another method.')
221
+ );
222
+ }
223
+
224
+ // Log the initial sale array, no protected data is included
225
+ Gene_Braintree_Model_Debug::log(array('_authorize:result' => $result));
226
+
227
+ // If the sale has failed
228
+ if ($result->success != true) {
229
+
230
+ // Dispatch an event for when a payment fails
231
+ Mage::dispatchEvent('gene_braintree_creditcard_failed', array('payment' => $payment, 'result' => $result));
232
+
233
+ // Return a different message for declined cards
234
+ if(isset($result->transaction->status) && $result->transaction->status == Braintree_Transaction::PROCESSOR_DECLINED) {
235
+ Mage::throwException($this->_getHelper()->__('Your transaction has been declined, please try another payment method or contacting your issuing bank.'));
236
+ }
237
+
238
+ Mage::throwException($this->_getHelper()->__('%s. Please try again or attempt refreshing the page.', $result->message));
239
+ }
240
+
241
+ // If 3D is enabled and the transaction gets a rejection reason
242
+ if($this->is3DEnabled()) {
243
+
244
+ // Check the rejection reason
245
+ if (isset($result->transaction) && $result->transaction->gatewayRejectionReason == Braintree_Transaction::THREE_D_SECURE) {
246
+
247
+ // An event for when 3D secure fails
248
+ Mage::dispatchEvent('gene_braintree_creditcard_failed_threed', array('payment' => $payment, 'result' => $result));
249
+
250
+ // Log it
251
+ Gene_Braintree_Model_Debug::log('Transaction failed with 3D secure');
252
+
253
+ // Politely inform the user
254
+ Mage::throwException(
255
+ $this->_getHelper()->__('Your 3D secure verification has failed, please try using another card, or payment method.')
256
+ );
257
+ }
258
+ }
259
+
260
+ $this->_processSuccessResult($payment, $result, $amount);
261
+
262
+ return $this;
263
+ }
264
+
265
+ /**
266
+ * Authorize the requested amount
267
+ * @param Varien_Object $payment
268
+ * @param float $amount
269
+ *
270
+ * @return Mage_Payment_Model_Abstract|void
271
+ * @throws Mage_Core_Exception
272
+ */
273
+ public function authorize(Varien_Object $payment, $amount)
274
+ {
275
+ $this->_authorize($payment, $amount, false);
276
+ }
277
+
278
+ /**
279
+ * Process capturing of a payment
280
+ * @param Varien_Object $payment
281
+ * @param float $amount
282
+ *
283
+ * @return Mage_Payment_Model_Abstract|void
284
+ */
285
+ public function capture(Varien_Object $payment, $amount)
286
+ {
287
+ // Has the payment already been authorized?
288
+ if ($payment->getCcTransId()) {
289
+
290
+ // Init the environment
291
+ $result = $this->_getWrapper()->init()->submitForSettlement($payment->getCcTransId(), $amount);
292
+
293
+ // Log the result
294
+ Gene_Braintree_Model_Debug::log(array('capture:submitForSettlement' => $result));
295
+
296
+ if($result->success) {
297
+ $this->_processSuccessResult($payment, $result, $amount);
298
+ } else if($result->errors->deepSize() > 0) {
299
+ Mage::throwException($result->errors);
300
+ } else {
301
+ Mage::throwException($result->transaction->processorSettlementResponseCode.': '.$result->transaction->processorSettlementResponseText);
302
+ }
303
+
304
+ } else {
305
+ // Otherwise we need to do an auth & capture at once
306
+ $this->_authorize($payment, $amount, true);
307
+ }
308
+
309
+ return $this;
310
+ }
311
+
312
+ /**
313
+ * Processes successful authorize/clone result
314
+ *
315
+ * @param Varien_Object $payment
316
+ * @param Braintree_Result_Successful $result
317
+ * @param decimal amount
318
+ * @return Varien_Object
319
+ */
320
+ protected function _processSuccessResult(Varien_Object $payment, $result, $amount)
321
+ {
322
+ // Pass an event if the payment was a success
323
+ Mage::dispatchEvent('gene_braintree_creditcard_success', array('payment' => $payment, 'result' => $result, 'amount' => $amount));
324
+
325
+ // Set some basic information about the payment
326
+ $payment->setStatus(self::STATUS_APPROVED)
327
+ ->setCcTransId($result->transaction->id)
328
+ ->setLastTransId($result->transaction->id)
329
+ ->setTransactionId($result->transaction->id)
330
+ ->setIsTransactionClosed(0)
331
+ ->setAmount($amount)
332
+ ->setShouldCloseParentTransaction(false);
333
+
334
+ // Set information about the card
335
+ $payment->setCcLast4($result->transaction->creditCardDetails->last4)
336
+ ->setCcType($result->transaction->creditCardDetails->cardType)
337
+ ->setCcExpMonth($result->transaction->creditCardDetails->expirationMonth)
338
+ ->setCcExpYear($result->transaction->creditCardDetails->expirationYear);
339
+
340
+ // Additional information to store
341
+ $additionalInfo = array();
342
+
343
+ // The fields within the transaction to log
344
+ $storeFields = array(
345
+ 'avsErrorResponseCode',
346
+ 'avsPostalCodeResponseCode',
347
+ 'avsStreetAddressResponseCode',
348
+ 'cvvResponseCode',
349
+ 'gatewayRejectionReason',
350
+ 'processorAuthorizationCode',
351
+ 'processorResponseCode',
352
+ 'processorResponseText',
353
+ 'threeDSecure'
354
+ );
355
+
356
+ // If 3D secure is enabled, presume it's passed
357
+ if($this->is3DEnabled()) {
358
+ $additionalInfo['threeDSecure'] = Mage::helper('gene_braintree')->__('Passed');
359
+ }
360
+
361
+ // Iterate through and pull out any data we want
362
+ foreach($storeFields as $storeField) {
363
+ if(!empty($result->transaction->{$storeField})) {
364
+ $additionalInfo[$storeField] = $result->transaction->{$storeField};
365
+ }
366
+ }
367
+
368
+ // Check it's not empty and store it
369
+ if(!empty($additionalInfo)) {
370
+ $payment->setAdditionalInformation($additionalInfo);
371
+ }
372
+
373
+ if (isset($result->transaction->creditCard['token']) && $result->transaction->creditCard['token']) {
374
+ $payment->setAdditionalInformation('token', $result->transaction->creditCard['token']);
375
+ }
376
+
377
+ return $payment;
378
+ }
379
+
380
+ }
app/code/community/Gene/Braintree/Model/Paymentmethod/Paypal.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Paymentmethod_Paypal
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Paymentmethod_Paypal extends Gene_Braintree_Model_Paymentmethod_Abstract
9
+ {
10
+ /**
11
+ * Setup block types
12
+ *
13
+ * @var string
14
+ */
15
+ protected $_formBlockType = 'gene_braintree/paypal';
16
+ protected $_infoBlockType = 'gene_braintree/paypal_info';
17
+
18
+ /**
19
+ * Set the code
20
+ *
21
+ * @var string
22
+ */
23
+ protected $_code = 'gene_braintree_paypal';
24
+
25
+ /**
26
+ * Payment Method features
27
+ *
28
+ * @var bool
29
+ */
30
+ protected $_isGateway = false;
31
+ protected $_canOrder = false;
32
+ protected $_canAuthorize = false;
33
+ protected $_canCapture = true;
34
+ protected $_canCapturePartial = false;
35
+ protected $_canRefund = false;
36
+ protected $_canRefundInvoicePartial = false;
37
+ protected $_canVoid = false;
38
+ protected $_canUseInternal = false;
39
+ protected $_canUseCheckout = true;
40
+ protected $_canUseForMultishipping = false;
41
+ protected $_isInitializeNeeded = false;
42
+ protected $_canFetchTransactionInfo = false;
43
+ protected $_canReviewPayment = false;
44
+ protected $_canCreateBillingAgreement = false;
45
+ protected $_canManageRecurringProfiles = false;
46
+
47
+ /**
48
+ * Is the vault enabled?
49
+ *
50
+ * @return bool
51
+ */
52
+ public function isVaultEnabled()
53
+ {
54
+ if ($this->_getConfig('payment_type') == Gene_Braintree_Model_Source_Paypal_Paymenttype::GENE_BRAINTREE_PAYPAL_FUTURE_PAYMENTS
55
+ && $this->_getConfig('use_vault'))
56
+ {
57
+ return true;
58
+ }
59
+ return false;
60
+ }
61
+
62
+ /**
63
+ * Capture the payment on the checkout page
64
+ *
65
+ * @param Varien_Object $payment
66
+ * @param float $amount
67
+ *
68
+ * @return Mage_Payment_Model_Abstract
69
+ */
70
+ public function capture(Varien_Object $payment, $amount)
71
+ {
72
+ // Retrieve the payment data from the request
73
+ $paymentPost = Mage::app()->getRequest()->getPost('payment');
74
+
75
+ // Confirm that we have a nonce from Braintree
76
+ if(!isset($paymentPost['paypal_payment_method_token'])) {
77
+ if ((!isset($paymentPost['payment_method_nonce']) || empty($paymentPost['payment_method_nonce']))) {
78
+ Mage::throwException(
79
+ $this->_getHelper()->__('There has been an issue processing your PayPal payment, please try again.')
80
+ );
81
+ }
82
+ } else if(isset($paymentPost['paypal_payment_method_token']) && empty($paymentPost['paypal_payment_method_token'])) {
83
+ Mage::throwException(
84
+ $this->_getHelper()->__('There has been an issue processing your PayPal payment, please try again.')
85
+ );
86
+ }
87
+
88
+ // Get the device data for fraud screening
89
+ $deviceData = Mage::app()->getRequest()->getPost('device_data');
90
+
91
+ // Init the environment
92
+ $this->_getWrapper()->init();
93
+
94
+ if(isset($paymentPost['paypal_payment_method_token']) && !empty($paymentPost['paypal_payment_method_token']) && $paymentPost['paypal_payment_method_token'] != 'other') {
95
+ $paymentArray = array(
96
+ 'paymentMethodToken' => $paymentPost['paypal_payment_method_token']
97
+ );
98
+ } else {
99
+ $paymentArray = array(
100
+ 'paymentMethodNonce' => $paymentPost['payment_method_nonce']
101
+ );
102
+ }
103
+
104
+ // Retrieve the amount we should capture
105
+ $amount = $this->_getWrapper()->getCaptureAmount($payment->getOrder(), $amount);
106
+
107
+ // Attempt to create the sale
108
+ try {
109
+ // Build the array for the sale
110
+ $saleArray = $this->_getWrapper()->buildSale(
111
+ $amount,
112
+ $paymentArray,
113
+ $payment->getOrder(),
114
+ true,
115
+ $deviceData,
116
+ ($this->isVaultEnabled() && isset($paymentPost['save_paypal']) && $paymentPost['save_paypal'] == 1)
117
+ );
118
+
119
+ // Pass the sale array into a varien object
120
+ $request = new Varien_Object();
121
+ $request->setData('sale_array', $saleArray);
122
+
123
+ // Dispatch event for modifying the sale array
124
+ Mage::dispatchEvent('gene_braintree_paypal_sale_array', array('payment' => $payment, 'request' => $request));
125
+
126
+ // Pull the saleArray back out
127
+ $saleArray = $request->getData('sale_array');
128
+
129
+ // Log the initial sale array, no protected data is included
130
+ Gene_Braintree_Model_Debug::log(array('saleArray' => $saleArray));
131
+
132
+ // Attempt to create the sale
133
+ $result = $this->_getWrapper()->makeSale(
134
+ $saleArray
135
+ );
136
+ } catch (Exception $e) {
137
+
138
+ // Dispatch an event for when a payment fails
139
+ Mage::dispatchEvent('gene_braintree_paypal_failed_exception', array('payment' => $payment, 'exception' => $e));
140
+
141
+ // If there's an error
142
+ Gene_Braintree_Model_Debug::log($e);
143
+
144
+ Mage::throwException(
145
+ $this->_getHelper()->__('We were unable to complete your purchase through PayPal, please try again or an alternative payment method.')
146
+ );
147
+ }
148
+
149
+ // Log the result
150
+ Gene_Braintree_Model_Debug::log(array('result' => $result));
151
+
152
+ // If the sale has failed
153
+ if ($result->success != true) {
154
+
155
+ // Dispatch an event for when a payment fails
156
+ Mage::dispatchEvent('gene_braintree_paypal_failed', array('payment' => $payment, 'result' => $result));
157
+
158
+ Mage::throwException($this->_getHelper()->__('%s. Please try again or attempt refreshing the page.', $result->message));
159
+ }
160
+
161
+ // Finish of the order
162
+ $this->_processSuccessResult($payment, $result, $amount);
163
+
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Process a successful result from the sale request
169
+ *
170
+ * @param Varien_Object $payment
171
+ * @param Braintree_Result_Successful $result
172
+ * @param $amount
173
+ *
174
+ * @return Varien_Object
175
+ */
176
+ protected function _processSuccessResult(Varien_Object $payment, $result, $amount)
177
+ {
178
+ // Pass an event if the payment was a success
179
+ Mage::dispatchEvent('gene_braintree_paypal_success', array('payment' => $payment, 'result' => $result, 'amount' => $amount));
180
+
181
+ // Set some basic things
182
+ $payment->setStatus(self::STATUS_APPROVED)
183
+ ->setCcTransId($result->transaction->id)
184
+ ->setLastTransId($result->transaction->id)
185
+ ->setTransactionId($result->transaction->id)
186
+ ->setIsTransactionClosed(0)
187
+ ->setAmount($amount)
188
+ ->setShouldCloseParentTransaction(false);
189
+
190
+ // Set the additioanl information about the customers PayPal account
191
+ $payment->setAdditionalInformation(
192
+ array(
193
+ 'paypal_email' => $result->transaction->paypal['payerEmail'],
194
+ 'payment_id' => $result->transaction->paypal['paymentId'],
195
+ 'authorization_id' => $result->transaction->paypal['authorizationId'],
196
+ )
197
+ );
198
+
199
+ // Store the PayPal token if we have one
200
+ if (isset($result->transaction->paypal['token']) && !empty($result->transaction->paypal['token'])) {
201
+ $payment->setAdditionalInformation('token', $result->transaction->paypal['token']);
202
+ }
203
+
204
+ // Save the payment data
205
+ $payment->save();
206
+
207
+ return $payment;
208
+ }
209
+
210
+ }
app/code/community/Gene/Braintree/Model/Saved.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Gene_Braintree_Model_Saved
4
+ *
5
+ * @author Dave Macaulay <dave@gene.co.uk>
6
+ */
7
+ class Gene_Braintree_Model_Saved extends Mage_Core_Model_Abstract
8
+ {
9
+
10
+ /**
11
+ * The ID's associated with the two different payment methods
12
+ */
13
+ const SAVED_PAYPAL_ID = 1;
14
+ const SAVED_CREDITCARD_ID = 2;
15
+
16
+ private $savedAccounts = false;
17
+
18
+ /**
19
+ * Get the current customers saved cards
20
+ *
21
+ * @return array
22
+ */
23
+ public function getCustomerSavedPaymentMethods()
24
+ {
25
+ // Grab an instance of the customers session
26
+ $customerSession = Mage::getSingleton('customer/session');
27
+
28
+ // You can only store cards if you're logged in
29
+ if($customerSession->isLoggedIn() && $customerSession->getCustomer()->getBraintreeCustomerId()) {
30
+
31
+ if(!$this->savedAccounts) {
32
+
33
+ // Grab a new instance of the wrapper
34
+ $wrapper = Mage::getModel('gene_braintree/wrapper_braintree');
35
+
36
+ // Init the braintree wrapper
37
+ $wrapper->init();
38
+
39
+ // Try and load the customer from Braintrees side
40
+ if ($customer = $wrapper->getCustomer($customerSession->getCustomer()->getBraintreeCustomerId())) {
41
+
42
+ // Assign them into our model
43
+ $this->savedAccounts = array_merge($customer->creditCards, $customer->paypalAccounts);
44
+ }
45
+
46
+ }
47
+
48
+ return $this->savedAccounts;
49
+
50
+ }
51
+
52
+ return false;
53
+ }
54
+
55
+ /**
56
+ * Return a boolean value on whether the customer has a certain type of payment method
57
+ *
58
+ * @param bool $type
59
+ *
60
+ * @return bool|int
61
+ */
62
+ public function hasType($type = false)
63
+ {
64
+ // If no type is set just count the saved methods
65
+ if(!$type) {
66
+ if(!$this->getCustomerSavedPaymentMethods()) {
67
+ return false;
68
+ }
69
+ return count($this->getCustomerSavedPaymentMethods());
70
+ }
71
+
72
+ // Check there are some saved accounts
73
+ if($savedAccounts = $this->getCustomerSavedPaymentMethods()) {
74
+
75
+ // Iterate through the saved accounts
76
+ foreach ($savedAccounts as $savedAccount) {
77
+
78
+ // Check which type we're after
79
+ if ($type == Gene_Braintree_Model_Saved::SAVED_CREDITCARD_ID) {
80
+ if ($savedAccount instanceof Braintree_CreditCard) {
81
+ return true;
82
+ }
83
+ } elseif ($type == Gene_Braintree_Model_Saved::SAVED_PAYPAL_ID) {
84
+ if ($savedAccount instanceof Braintree_PayPalAccount) {
85
+ return true;
86
+ }
87
+ }
88
+
89
+ }
90
+ }
91
+
92
+ return false;
93
+ }
94
+
95
+ /**
96
+ * Return only those accounts which are a certain type
97
+
98
+ * @param $type
99
+ *
100
+ * @return array
101
+ */
102
+ public function getSavedMethodsByType($type = false)
103
+ {
104
+ if(!$type) {
105
+ return $this->getCustomerSavedPaymentMethods();
106
+ }
107
+
108
+ // Start up our new collection
109
+ $savedDetails = array();
110
+
111
+ if($this->getCustomerSavedPaymentMethods()) {
112
+ foreach ($this->getCustomerSavedPaymentMethods() as $savedAccount) {
113
+
114
+ // Check which type we're after
115
+ if ($type == Gene_Braintree_Model_Saved::SAVED_CREDITCARD_ID) {
116
+ if ($savedAccount instanceof Braintree_CreditCard) {
117
+ $savedDetails[] = $savedAccount;
118
+ }
119
+ } elseif ($type == Gene_Braintree_Model_Saved::SAVED_PAYPAL_ID) {
120
+ if ($savedAccount instanceof Braintree_PayPalAccount) {
121
+ $savedDetails[] = $savedAccount;
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ return $savedDetails;
128
+ }
129
+
130
+ }
app/code/community/Gene/Braintree/Model/Source/Cctype.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Source_Cctype
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Source_Cctype extends Mage_Payment_Model_Source_Cctype
9
+ {
10
+ /**
11
+ * Allowed credit card types
12
+ * This list includes a separate entry for Maestro
13
+ *
14
+ * @return array
15
+ */
16
+ public function getAllowedTypes()
17
+ {
18
+ return array(
19
+ 'VI',
20
+ 'MC',
21
+ 'AE',
22
+ 'DI',
23
+ 'JCB',
24
+ 'OT',
25
+ 'ME'
26
+ );
27
+ }
28
+ }
app/code/community/Gene/Braintree/Model/Source/Creditcard/CaptureAction.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Source_Creditcard_CaptureAction
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Source_Creditcard_CaptureAction
9
+ {
10
+
11
+ const CAPTURE_ACTION_XML_PATH = 'payment/gene_braintree_creditcard/capture_action';
12
+
13
+ const CAPTURE_INVOICE = 'invoice';
14
+ const CAPTURE_SHIPMENT = 'shipment';
15
+
16
+ /**
17
+ * Possible actions on order place
18
+ *
19
+ * @return array
20
+ */
21
+ public function toOptionArray()
22
+ {
23
+ return array(
24
+ array(
25
+ 'value' => self::CAPTURE_INVOICE,
26
+ 'label' => Mage::helper('gene_braintree')->__('Invoice')
27
+ ),
28
+ array(
29
+ 'value' => self::CAPTURE_SHIPMENT,
30
+ 'label' => Mage::helper('gene_braintree')->__('Shipment')
31
+ ),
32
+ );
33
+ }
34
+ }
app/code/community/Gene/Braintree/Model/Source/Creditcard/PaymentAction.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Source_Creditcard_PaymentAction
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Source_Creditcard_PaymentAction
9
+ {
10
+
11
+ const PAYMENT_ACTION_XML_PATH = 'payment/gene_braintree_creditcard/payment_action';
12
+
13
+ /**
14
+ * Possible actions on order place
15
+ *
16
+ * @return array
17
+ */
18
+ public function toOptionArray()
19
+ {
20
+ return array(
21
+ array(
22
+ 'value' => Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE,
23
+ 'label' => Mage::helper('gene_braintree')->__('Authorize')
24
+ ),
25
+ array(
26
+ 'value' => Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE_CAPTURE,
27
+ 'label' => Mage::helper('gene_braintree')->__('Authorize & Capture')
28
+ ),
29
+ );
30
+ }
31
+ }
app/code/community/Gene/Braintree/Model/Source/Environment.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Braintree_Payments_Model_Source_Environment
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Source_Environment
9
+ {
10
+ /**
11
+ * Display both sandbox and production values
12
+ *
13
+ * @return array
14
+ */
15
+ public function toOptionArray()
16
+ {
17
+ return array(
18
+ array(
19
+ 'value' => 'sandbox',
20
+ 'label' => Mage::helper('gene_braintree')->__('Sandbox'),
21
+ ),
22
+ array(
23
+ 'value' => 'production',
24
+ 'label' => Mage::helper('gene_braintree')->__('Production')
25
+ )
26
+ );
27
+ }
28
+ }
app/code/community/Gene/Braintree/Model/Source/Paypal/Locale.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Source_Paypal_Locale
5
+ * @author Dave Macaulay <dave@gene.co.uk>
6
+ */
7
+ class Gene_Braintree_Model_Source_Paypal_Locale
8
+ {
9
+
10
+ /**
11
+ * Return the array of options
12
+ * @return array
13
+ */
14
+ public function getArray()
15
+ {
16
+ return array(
17
+ 'en_au' => Mage::helper('gene_braintree')->__('Australia'),
18
+ 'en_ca' => Mage::helper('gene_braintree')->__('Canada'),
19
+ 'fr_fr' => Mage::helper('gene_braintree')->__('France'),
20
+ 'de_de' => Mage::helper('gene_braintree')->__('Germany'),
21
+ 'en_gb' => Mage::helper('gene_braintree')->__('Great Britain & Ireland'),
22
+ 'zh_hk' => Mage::helper('gene_braintree')->__('Hong Kong'),
23
+ 'it_it' => Mage::helper('gene_braintree')->__('Italy'),
24
+ 'es_es' => Mage::helper('gene_braintree')->__('Spain'),
25
+ 'en_us' => Mage::helper('gene_braintree')->__('United States')
26
+ );
27
+ }
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ $response = array();
36
+ foreach($this->getArray() as $key => $value) {
37
+ $response[] = array(
38
+ 'value' => $key,
39
+ 'label' => $value
40
+ );
41
+ }
42
+ return $response;
43
+ }
44
+
45
+ /**
46
+ * Get options in "key-value" format
47
+ *
48
+ * @return array
49
+ */
50
+ public function toArray()
51
+ {
52
+ return $this->getArray();
53
+ }
54
+
55
+ }
app/code/community/Gene/Braintree/Model/Source/Paypal/Paymenttype.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Source_Paypal_Paymenttype
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Source_Paypal_Paymenttype
9
+ {
10
+
11
+ const GENE_BRAINTREE_PAYPAL_SINGLE_PAYMENT = 'single';
12
+ const GENE_BRAINTREE_PAYPAL_FUTURE_PAYMENTS = 'future';
13
+
14
+ /**
15
+ * Return our options
16
+ *
17
+ * @return array
18
+ */
19
+ public function toOptionArray()
20
+ {
21
+ return array(
22
+ array(
23
+ 'value' => self::GENE_BRAINTREE_PAYPAL_SINGLE_PAYMENT,
24
+ 'label' => Mage::helper('gene_braintree')->__('Single Payment'),
25
+ ),
26
+ array(
27
+ 'value' => self::GENE_BRAINTREE_PAYPAL_FUTURE_PAYMENTS,
28
+ 'label' => Mage::helper('gene_braintree')->__('Future Payments')
29
+ )
30
+ );
31
+ }
32
+
33
+ }
app/code/community/Gene/Braintree/Model/System/Config/Backend/Currency.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_System_Config_Backend_Currency
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_System_Config_Backend_Currency extends Mage_Core_Model_Config_Data
9
+ {
10
+
11
+ /**
12
+ * Json decode the value
13
+ */
14
+ protected function _afterLoad()
15
+ {
16
+ if (!is_array($this->getValue())) {
17
+ $value = $this->getValue();
18
+ $this->setValue(empty($value) ? false : json_decode($value));
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Json encode the value to be stored in the database
24
+ */
25
+ protected function _beforeSave()
26
+ {
27
+ if (is_array($this->getValue())) {
28
+ $this->setValue(json_encode($this->getValue()));
29
+ }
30
+ }
31
+
32
+ }
app/code/community/Gene/Braintree/Model/Wrapper/Braintree.php ADDED
@@ -0,0 +1,729 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Model_Wrapper_Braintree
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Model_Wrapper_Braintree extends Mage_Core_Model_Abstract
9
+ {
10
+
11
+ CONST BRAINTREE_ENVIRONMENT_PATH = 'payment/gene_braintree/environment';
12
+ CONST BRAINTREE_MERCHANT_ID_PATH = 'payment/gene_braintree/merchant_id';
13
+ CONST BRAINTREE_MERCHANT_ACCOUNT_ID_PATH = 'payment/gene_braintree/merchant_account_id';
14
+ CONST BRAINTREE_PUBLIC_KEY_PATH = 'payment/gene_braintree/public_key';
15
+ CONST BRAINTREE_PRIVATE_KEY_PATH = 'payment/gene_braintree/private_key';
16
+
17
+ const BRAINTREE_MULTI_CURRENCY = 'payment/gene_braintree/multi_currency_enable';
18
+ const BRAINTREE_MULTI_CURRENCY_MAPPING = 'payment/gene_braintree/multi_currency_mapping';
19
+
20
+ /**
21
+ * Store the customer
22
+ *
23
+ * @var Braintree_Customer
24
+ */
25
+ private $customer;
26
+
27
+ /**
28
+ * Store the Braintree ID
29
+ *
30
+ * @var int
31
+ */
32
+ private $braintreeId;
33
+
34
+ /**
35
+ * Used to track whether the payment methods are available
36
+ *
37
+ * @var bool
38
+ */
39
+ private $validated = null;
40
+
41
+ /**
42
+ * If we're using a mapped currency we need to charge the grand total, instead of the base
43
+ *
44
+ * @var bool
45
+ */
46
+ private $mappedCurrency = false;
47
+
48
+ /**
49
+ * Store whether or not we've init the environment yet
50
+ *
51
+ * @var bool
52
+ */
53
+ private $init = false;
54
+
55
+ /**
56
+ * Setup the environment
57
+ *
58
+ * @return $this
59
+ */
60
+ public function init($store = null)
61
+ {
62
+ if(!$this->init) {
63
+
64
+ // Setup the various configuration variables
65
+ Braintree_Configuration::environment(Mage::getStoreConfig(self::BRAINTREE_ENVIRONMENT_PATH, $store));
66
+ Braintree_Configuration::merchantId(Mage::getStoreConfig(self::BRAINTREE_MERCHANT_ID_PATH, $store));
67
+ Braintree_Configuration::publicKey(Mage::getStoreConfig(self::BRAINTREE_PUBLIC_KEY_PATH, $store));
68
+ Braintree_Configuration::privateKey(Mage::getStoreConfig(self::BRAINTREE_PRIVATE_KEY_PATH, $store));
69
+
70
+ // Set our flag
71
+ $this->init = true;
72
+ }
73
+
74
+ return $this;
75
+ }
76
+
77
+ /**
78
+ * Find a transaction
79
+ *
80
+ * @param $transactionId
81
+ *
82
+ * @throws Braintree_Exception_NotFound
83
+ */
84
+ public function findTransaction($transactionId)
85
+ {
86
+ return Braintree_Transaction::find($transactionId);
87
+ }
88
+
89
+ /**
90
+ * If we're trying to charge a 3D secure card in the vault we need to build a special nonce
91
+ *
92
+ * @param $paymentMethodToken
93
+ *
94
+ * @return mixed
95
+ */
96
+ public function getThreeDSecureVaultNonce($paymentMethodToken)
97
+ {
98
+ $this->init();
99
+
100
+ $result = Braintree_PaymentMethodNonce::create($paymentMethodToken);
101
+ return $result->paymentMethodNonce->nonce;
102
+ }
103
+
104
+ /**
105
+ * Try and load the Braintree customer from the stored customer ID
106
+ *
107
+ * @param $braintreeCustomerId
108
+ *
109
+ * @return Braintree_Customer
110
+ */
111
+ public function getCustomer($braintreeCustomerId)
112
+ {
113
+ // Try and load it from the customer
114
+ if(!$this->customer && !isset($this->customer[$braintreeCustomerId])) {
115
+ try {
116
+ $this->customer[$braintreeCustomerId] = Braintree_Customer::find($braintreeCustomerId);
117
+ } catch (Exception $e) {
118
+ return false;
119
+ }
120
+ }
121
+
122
+ return $this->customer[$braintreeCustomerId];
123
+ }
124
+
125
+ /**
126
+ * Check to see whether this customer already exists
127
+ *
128
+ * @return bool|object
129
+ */
130
+ public function checkIsCustomer()
131
+ {
132
+ try {
133
+ // Check to see that we can generate a braintree ID
134
+ if($braintreeId = $this->getBraintreeId()) {
135
+
136
+ // Proxy this request to the other method which has caching
137
+ return $this->getCustomer($braintreeId);
138
+ }
139
+ } catch (Exception $e) {
140
+ return false;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Generate a server side token with the specified account ID
146
+ *
147
+ * @return mixed
148
+ */
149
+ public function generateToken()
150
+ {
151
+ // Use the class to generate the token
152
+ return Braintree_ClientToken::generate();
153
+ }
154
+
155
+
156
+ /**
157
+ * Check a customer owns the method we're trying to modify
158
+ *
159
+ * @param $paymentMethod
160
+ *
161
+ * @return bool
162
+ */
163
+ public function customerOwnsMethod($paymentMethod)
164
+ {
165
+ // Grab the customer ID from the customers account
166
+ $customerId = Mage::getSingleton('customer/session')->getCustomer()->getBraintreeCustomerId();
167
+
168
+ // Detect which type of payment method we've got here
169
+ if($paymentMethod instanceof Braintree_PayPalAccount) {
170
+
171
+ // Grab the customer
172
+ $customer = $this->getCustomer($customerId);
173
+
174
+ // Store all the tokens in an array
175
+ $customerTokens = array();
176
+
177
+ // Check the customer has PayPal Accounts
178
+ if(isset($customer->paypalAccounts)) {
179
+
180
+ /* @var $payPalAccount Braintree_PayPalAccount */
181
+ foreach($customer->paypalAccounts as $payPalAccount) {
182
+ if(isset($payPalAccount->token)) {
183
+ $customerTokens[] = $payPalAccount->token;
184
+ }
185
+ }
186
+ } else {
187
+ return false;
188
+ }
189
+
190
+ // Check to see if this customer account contains this token
191
+ if(in_array($paymentMethod->token, $customerTokens)) {
192
+ return true;
193
+ }
194
+
195
+ return false;
196
+
197
+ } else if(isset($paymentMethod->customerId) && $paymentMethod->customerId == $customerId) {
198
+
199
+ return true;
200
+ }
201
+
202
+ return false;
203
+ }
204
+
205
+ /**
206
+ * Retrieve the Braintree ID from Magento
207
+ *
208
+ * @return bool|string
209
+ */
210
+ protected function getBraintreeId()
211
+ {
212
+ // Some basic caching
213
+ if(!$this->braintreeId) {
214
+
215
+ // Is the customer already logged in
216
+ if (Mage::getSingleton('customer/session')->isLoggedIn()) {
217
+
218
+ // Retrieve the current customer
219
+ $customer = Mage::getSingleton('customer/session')->getCustomer();
220
+
221
+ // Determine whether they have a braintree customer ID already
222
+ if ($brainteeId = $customer->getBraintreeCustomerId()) {
223
+ $this->braintreeId = $customer->getBraintreeCustomerId();
224
+ } else {
225
+ // If not let's create them one
226
+ $this->braintreeId = $this->buildCustomerId();
227
+ $customer->setBraintreeCustomerId($this->braintreeId)->save();
228
+ }
229
+
230
+ } else {
231
+ if ((Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == 'login_in' || Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER)) {
232
+
233
+ // Check to see if we've already generated an ID
234
+ if($braintreeId = Mage::getSingleton('checkout/session')->getBraintreeCustomerId()) {
235
+ $this->braintreeId = $braintreeId;
236
+ } else {
237
+ // If the user plans to register let's build them an ID and store it in their session
238
+ $this->braintreeId = $this->buildCustomerId();
239
+ Mage::getSingleton('checkout/session')->setBraintreeCustomerId($this->braintreeId);
240
+ }
241
+ }
242
+ }
243
+
244
+ }
245
+
246
+ return $this->braintreeId;
247
+ }
248
+
249
+
250
+ /**
251
+ * Validate the credentials within the admin area
252
+ *
253
+ * @return bool
254
+ */
255
+ public function validateCredentials($prettyResponse = false, $alreadyInit = false, $merchantAccountId = false)
256
+ {
257
+ // Try to init the environment
258
+ try {
259
+ if(!$alreadyInit) {
260
+
261
+ // If we're within the admin we want to grab these values from whichever store we're modifying
262
+ if(Mage::app()->getStore()->isAdmin()) {
263
+ Braintree_Configuration::environment(Mage::getSingleton('adminhtml/config_data')->getConfigDataValue(self::BRAINTREE_ENVIRONMENT_PATH));
264
+ Braintree_Configuration::merchantId(Mage::getSingleton('adminhtml/config_data')->getConfigDataValue(self::BRAINTREE_MERCHANT_ID_PATH));
265
+ Braintree_Configuration::publicKey(Mage::getSingleton('adminhtml/config_data')->getConfigDataValue(self::BRAINTREE_PUBLIC_KEY_PATH));
266
+ Braintree_Configuration::privateKey(Mage::getSingleton('adminhtml/config_data')->getConfigDataValue(self::BRAINTREE_PRIVATE_KEY_PATH));
267
+ } else {
268
+ $this->init();
269
+ }
270
+ }
271
+ } catch (Exception $e) {
272
+
273
+ if($prettyResponse) {
274
+ return '<span style="color: red;font-weight: bold;" id="braintree-valid-config">' . Mage::helper('gene_braintree')->__('Invalid Credentials') . '</span><br />' . Mage::helper('gene_braintree')->__('Payments cannot be processed until this is resolved, due to this the methods will be hidden within the checkout');
275
+ }
276
+ return false;
277
+ }
278
+
279
+ // Check to see if we've been passed the merchant account ID?
280
+ if(!$merchantAccountId) {
281
+ if(Mage::app()->getStore()->isAdmin()) {
282
+ $merchantAccountId = Mage::getSingleton('adminhtml/config_data')->getConfigDataValue(self::BRAINTREE_MERCHANT_ACCOUNT_ID_PATH);
283
+ } else {
284
+ $merchantAccountId = $this->getMerchantAccountId();
285
+ }
286
+ }
287
+
288
+ // Validate the merchant account ID
289
+ try {
290
+ Braintree_Configuration::gateway()->merchantAccount()->find($merchantAccountId);
291
+ } catch (Exception $e) {
292
+ if($prettyResponse) {
293
+ return '<span style="color: orange;font-weight: bold;" id="braintree-valid-config">' . Mage::helper('gene_braintree')->__('Invalid Merchant Account ID') . '</span><br />' . Mage::helper('gene_braintree')->__('Payments cannot be processed until this is resolved. We cannot find your merchant account ID associated with the other credentials you\'ve provided, please update this field');
294
+ }
295
+ return false;
296
+ }
297
+
298
+ if($prettyResponse) {
299
+ return '<span style="color: green;font-weight: bold;" id="braintree-valid-config">' . Mage::helper('gene_braintree')->__('Valid Credentials') . '</span><br />' . Mage::helper('gene_braintree')->__('You\'re ready to accept payments via Braintree');
300
+ }
301
+ return true;
302
+ }
303
+
304
+ /**
305
+ * Validate the credentials once, this is used during the payment methods available check
306
+ * @return bool
307
+ */
308
+ public function validateCredentialsOnce()
309
+ {
310
+ // Check to see if it's been validated yet
311
+ if(is_null($this->validated)) {
312
+
313
+ // Check the Braintree lib version is above 2.32, as this is when 3D secure appeared
314
+ if (Braintree_Version::get() < 2.32) {
315
+ $this->validated = false;
316
+ } else {
317
+
318
+ // Check that the module is fully setup
319
+ if (!Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_ENVIRONMENT_PATH)
320
+ || !Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_MERCHANT_ID_PATH)
321
+ || !Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_PUBLIC_KEY_PATH)
322
+ || !Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_PRIVATE_KEY_PATH)
323
+ ) {
324
+ // If not the payment methods aren't available
325
+ $this->validated = false;
326
+
327
+ } else {
328
+
329
+ // Try and validate the stored credentials
330
+ if (!Mage::getModel('gene_braintree/wrapper_braintree')->validateCredentials()) {
331
+
332
+ // Only add this in if it's not the last notice
333
+ $latestNotice = Mage::getModel('adminnotification/inbox')->loadLatestNotice();
334
+
335
+ // Validate there is a latest notice
336
+ if ($latestNotice && $latestNotice->getId()) {
337
+
338
+ // Check to see if the title contains our error
339
+ // Magento does not provide a nice way of doing this that I'm aware of
340
+ if (strpos($latestNotice->getTitle(), 'Braintree Configuration Invalid') === false) {
341
+
342
+ // If it doesn't add it again!
343
+ Mage::getModel('adminnotification/inbox')->addMajor(Mage::helper('gene_braintree')->__('Braintree Configuration Invalid - %s - This could be stopping payments', Mage::app()->getStore()->getFrontendName()), Mage::helper('gene_braintree')->__('The configuration values in the Magento Braintree v.zero module are incorrect, until these values are corrected the system can not function. This occurred on store %s - ID: %s', Mage::app()->getStore()->getFrontendName(), Mage::app()->getStore()->getId()));
344
+ }
345
+
346
+ } else {
347
+
348
+ // Otherwise there hasn't been any other notices
349
+ Mage::getModel('adminnotification/inbox')->addMajor(Mage::helper('gene_braintree')->__('Braintree Configuration Invalid - %s - This could be stopping payments', Mage::app()->getStore()->getFrontendName()), Mage::helper('gene_braintree')->__('The configuration values in the Magento Braintree v.zero module are incorrect, until these values are corrected the system can not function. This occurred on store %s - ID: %s', Mage::app()->getStore()->getFrontendName(), Mage::app()->getStore()->getId()));
350
+ }
351
+
352
+ $this->validated = false;
353
+
354
+ } else {
355
+
356
+ // Otherwise the method validated
357
+ $this->validated = true;
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ return $this->validated;
364
+ }
365
+
366
+ /**
367
+ * Build up the sale request
368
+ *
369
+ * @param $amount
370
+ * @param array $paymentDataArray
371
+ * @param Mage_Sales_Model_Order $order
372
+ * @param bool $submitForSettlement
373
+ * @param bool $deviceData
374
+ * @param bool $storeInVault
375
+ * @param bool $threeDSecure
376
+ * @param array $extra
377
+ *
378
+ * @return array
379
+ *
380
+ * @throws Mage_Core_Exception
381
+ */
382
+ public function buildSale(
383
+ $amount,
384
+ array $paymentDataArray,
385
+ Mage_Sales_Model_Order $order,
386
+ $submitForSettlement = true,
387
+ $deviceData = false,
388
+ $storeInVault = false,
389
+ $threeDSecure = false,
390
+ $extra = array()
391
+ ) {
392
+ // Check we always have an ID
393
+ if (!$order->getIncrementId()) {
394
+ Mage::throwException('Your order has become invalid, please try refreshing.');
395
+ }
396
+
397
+ // Store whether or not we created a new method
398
+ $createdMethod = false;
399
+
400
+ // If the user is already a customer and wants to store in the vault we've gotta do something a bit special
401
+ if($storeInVault && $this->checkIsCustomer() && isset($paymentDataArray['paymentMethodNonce'])) {
402
+
403
+ // Create the payment method with this data
404
+ $paymentMethodCreate = array(
405
+ 'customerId' => $this->getBraintreeId(),
406
+ 'paymentMethodNonce' => $paymentDataArray['paymentMethodNonce'],
407
+ 'billingAddress' => $this->buildAddress($order->getBillingAddress())
408
+ );
409
+
410
+ // Log the create array
411
+ Gene_Braintree_Model_Debug::log(array('Braintree_PaymentMethod' => $paymentMethodCreate));
412
+
413
+ // Create a new billing method
414
+ $result = Braintree_PaymentMethod::create($paymentMethodCreate);
415
+
416
+ // Log the response from Braintree
417
+ Gene_Braintree_Model_Debug::log(array('Braintree_PaymentMethod:result' => $paymentMethodCreate));
418
+
419
+ // Verify the storing of the card was a success
420
+ if(isset($result->success) && $result->success == true) {
421
+
422
+ /* @var $paymentMethod Braintree_CreditCard */
423
+ $paymentMethod = $result->paymentMethod;
424
+
425
+ // Check to see if the token is set
426
+ if(isset($paymentMethod->token) && !empty($paymentMethod->token)) {
427
+
428
+ // We no longer need this nonce
429
+ unset($paymentDataArray['paymentMethodNonce']);
430
+
431
+ // Instead use the token
432
+ $paymentDataArray['paymentMethodToken'] = $paymentMethod->token;
433
+
434
+ // Create a flag for other methods
435
+ $createdMethod = true;
436
+ }
437
+
438
+ } else {
439
+ Mage::throwException($result->message . Mage::helper('gene_braintree')->__(' Please try again or attempt refreshing the page.'));
440
+ }
441
+ }
442
+
443
+ // Build up the initial request parameters
444
+ $request = array(
445
+ 'amount' => $amount,
446
+ 'orderId' => $order->getIncrementId(),
447
+ 'merchantAccountId' => $this->getMerchantAccountId(),
448
+ 'channel' => 'MagentoVZero',
449
+ 'options' => array(
450
+ 'submitForSettlement' => $submitForSettlement,
451
+ 'storeInVault' => $storeInVault
452
+ )
453
+ );
454
+
455
+ // Input the allowed payment method info
456
+ $allowedPaymentInfo = array('paymentMethodNonce','paymentMethodToken','token','cvv');
457
+ foreach($paymentDataArray as $key => $value) {
458
+ if(in_array($key, $allowedPaymentInfo)) {
459
+ if($key == 'cvv') {
460
+ $request['creditCard']['cvv'] = $value;
461
+ } else {
462
+ $request[$key] = $value;
463
+ }
464
+ } else {
465
+ Mage::throwException($key.' is not allowed within $paymentDataArray');
466
+ }
467
+ }
468
+
469
+ // Include the customer if we're creating a new one
470
+ if(!$this->checkIsCustomer() && (Mage::getSingleton('customer/session')->isLoggedIn() ||
471
+ (Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == 'login_in' || Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod() == Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER))) {
472
+ $request['customer'] = $this->buildCustomer($order);
473
+ } else {
474
+ // If the customer exists but we aren't using the vault we want to pass a customer object with no ID
475
+ $request['customer'] = $this->buildCustomer($order, false);
476
+ }
477
+
478
+ // Do we have any deviceData to send over?
479
+ if ($deviceData) {
480
+ $request['deviceData'] = $deviceData;
481
+ }
482
+
483
+ // Include the shipping address
484
+ if ($order->getShippingAddress()) {
485
+ $request['shipping'] = $this->buildAddress($order->getShippingAddress());
486
+ }
487
+
488
+ // Include the billing address
489
+ if ($order->getBillingAddress()) {
490
+ $request['billing'] = $this->buildAddress($order->getBillingAddress());
491
+ }
492
+
493
+ // Is 3D secure enabled?
494
+ if($threeDSecure !== false && !$createdMethod) {
495
+ $request['options']['three_d_secure']['required'] = true;
496
+ }
497
+
498
+ // Any extra information we want to supply
499
+ if(!empty($extra) && is_array($extra)) {
500
+ $request = array_merge($request, $extra);
501
+ }
502
+
503
+ return $request;
504
+ }
505
+
506
+ /**
507
+ * Attempt to make the sale
508
+ *
509
+ * @param $saleArray
510
+ *
511
+ * @return stdClass
512
+ */
513
+ public function makeSale($saleArray)
514
+ {
515
+ // Call the braintree library
516
+ return Braintree_Transaction::sale(
517
+ $saleArray
518
+ );
519
+ }
520
+
521
+ /**
522
+ * Submit a payment for settlement
523
+ *
524
+ * @param $transactionId
525
+ * @param $amount
526
+ *
527
+ * @throws Mage_Core_Exception
528
+ */
529
+ public function submitForSettlement($transactionId, $amount)
530
+ {
531
+ // Attempt to submit for settlement
532
+ $result = Braintree_Transaction::submitForSettlement($transactionId, $amount);
533
+
534
+ return $result;
535
+ }
536
+
537
+ /**
538
+ * Build the customers ID, md5 a uniquid
539
+ *
540
+ * @param Mage_Sales_Model_Order $order
541
+ *
542
+ * @return string
543
+ * @throws Mage_Core_Exception
544
+ */
545
+ private function buildCustomerId()
546
+ {
547
+ return md5(uniqid('braintree_',true));
548
+ }
549
+
550
+ /**
551
+ * Build a Magento address model into a Braintree array
552
+ *
553
+ * @param Mage_Sales_Model_Order_Address $address
554
+ *
555
+ * @return array
556
+ */
557
+ private function buildAddress(Mage_Sales_Model_Order_Address $address)
558
+ {
559
+ // Build up the initial array
560
+ $return = array(
561
+ 'firstName' => $address->getFirstname(),
562
+ 'lastName' => $address->getLastname(),
563
+ 'streetAddress' => $address->getStreet1(),
564
+ 'locality' => $address->getCity(),
565
+ 'postalCode' => $address->getPostcode(),
566
+ 'countryCodeAlpha2' => $address->getCountry()
567
+ );
568
+
569
+ // Any extended address?
570
+ if ($address->getStreet2()) {
571
+ $return['extendedAddress'] = $address->getStreet2();
572
+ }
573
+
574
+ // Region
575
+ if ($address->getRegion()) {
576
+ $return['region'] = $address->getRegionCode();
577
+ }
578
+
579
+ // Check to see if we have a company
580
+ if ($address->getCompany()) {
581
+ $return['company'] = $address->getCompany();
582
+ }
583
+
584
+ return $return;
585
+ }
586
+
587
+ /**
588
+ * Return the correct merchant account ID
589
+ *
590
+ * @return mixed
591
+ */
592
+ public function getMerchantAccountId()
593
+ {
594
+ // If multi-currency is enabled use the mapped merchant account ID
595
+ if($currencyCode = $this->hasMappedCurrencyCode()) {
596
+
597
+ // Return the mapped currency code
598
+ return $currencyCode;
599
+ }
600
+
601
+ // Otherwise return the one from the store
602
+ return Mage::getStoreConfig(self::BRAINTREE_MERCHANT_ACCOUNT_ID_PATH);
603
+ }
604
+
605
+ /**
606
+ * If we have a mapped currency code reutrn it
607
+ *
608
+ * @return bool
609
+ */
610
+ public function hasMappedCurrencyCode()
611
+ {
612
+ // If multi-currency is enabled use the mapped merchant account ID
613
+ if($this->currencyMappingEnabled()) {
614
+
615
+ // Retrieve the mapping from the config
616
+ $mapping = Mage::helper('core')->jsonDecode(Mage::getStoreConfig(self::BRAINTREE_MULTI_CURRENCY_MAPPING));
617
+
618
+ // Verify it decoded correctly
619
+ if(is_array($mapping) && !empty($mapping)) {
620
+
621
+ // If we're in the admin get the currency code from the admin session quote
622
+ if(Mage::app()->getStore()->isAdmin()) {
623
+ $currency = $this->getAdminCurrency();
624
+ } else {
625
+ // Retrieve the current from the session
626
+ $currency = Mage::app()->getStore()->getCurrentCurrencyCode();
627
+ }
628
+
629
+ // Verify we have a mapping value for this currency
630
+ if(isset($mapping[$currency]) && !empty($mapping[$currency])) {
631
+
632
+ return $mapping[$currency];
633
+ }
634
+ }
635
+ }
636
+
637
+ return false;
638
+ }
639
+
640
+ /**
641
+ * Do we have currency mapping enabled?
642
+ *
643
+ * @return bool
644
+ */
645
+ public function currencyMappingEnabled()
646
+ {
647
+ return Mage::getStoreConfigFlag(self::BRAINTREE_MULTI_CURRENCY)
648
+ && Mage::getStoreConfig(self::BRAINTREE_MULTI_CURRENCY_MAPPING)
649
+ && (Mage::app()->getStore()->getCurrentCurrencyCode() || (Mage::app()->getStore()->isAdmin() && $this->getAdminCurrency()));
650
+ }
651
+
652
+ /**
653
+ * If we have a mapped currency code we need to convert the currency
654
+ *
655
+ * @param $amount
656
+ *
657
+ * @return mixed
658
+ */
659
+ public function getCaptureAmount(Mage_Sales_Model_Order $order, $amount)
660
+ {
661
+ // If we've got a mapped currency code the amount is going to change
662
+ if($currencyCode = $this->hasMappedCurrencyCode()) {
663
+
664
+ // Convert the current
665
+ $convertedCurrency = Mage::helper('directory')->currencyConvert($amount, $order->getBaseCurrencyCode(), $currencyCode);
666
+
667
+ // Format it to a precision of 2
668
+ $options = array(
669
+ 'currency' => $currencyCode,
670
+ 'display' => ''
671
+ );
672
+
673
+ return Mage::app()->getLocale()->currency($currencyCode)->toCurrency($convertedCurrency, $options);
674
+ }
675
+
676
+ return $amount;
677
+ }
678
+
679
+ /**
680
+ * Retrieve the admin currency
681
+ *
682
+ * @return bool
683
+ */
684
+ private function getAdminCurrency()
685
+ {
686
+ $order = Mage::app()->getRequest()->getPost('order');
687
+ if(isset($order['currency']) && !empty($order['currency'])) {
688
+ return $order['currency'];
689
+ }
690
+
691
+ return false;
692
+ }
693
+
694
+ /**
695
+ * Build up the customers data onto an object
696
+ *
697
+ * @param Mage_Sales_Model_Order $order
698
+ *
699
+ * @return array
700
+ */
701
+ private function buildCustomer(Mage_Sales_Model_Order $order, $includeId = true)
702
+ {
703
+ $customer = array(
704
+ 'firstName' => $order->getCustomerFirstname(),
705
+ 'lastName' => $order->getCustomerLastname(),
706
+ 'email' => $order->getCustomerEmail(),
707
+ 'phone' => $order->getBillingAddress()->getTelephone()
708
+ );
709
+
710
+ // Shall we include the customer ID?
711
+ if($includeId) {
712
+ $customer['id'] = $this->getBraintreeId();
713
+ }
714
+
715
+ // Handle empty data with alternatives
716
+ if(empty($customer['firstName'])) {
717
+ $customer['firstName'] = $order->getBillingAddress()->getFirstname();
718
+ }
719
+ if(empty($customer['lastName'])) {
720
+ $customer['lastName'] = $order->getBillingAddress()->getLastname();
721
+ }
722
+ if(empty($customer['email'])) {
723
+ $customer['email'] = $order->getBillingAddress()->getEmail();
724
+ }
725
+
726
+ return $customer;
727
+ }
728
+
729
+ }
app/code/community/Gene/Braintree/controllers/Adminhtml/BraintreeController.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_Adminhtml_BraintreeController
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_Adminhtml_BraintreeController extends Mage_Adminhtml_Controller_Action
9
+ {
10
+
11
+ /**
12
+ * Settlement report from Braintree
13
+ */
14
+ public function transactionsAction()
15
+ {
16
+ $this->loadLayout();
17
+
18
+ $this->_title(Mage::helper('gene_braintree')->__('Braintree Transactions'));
19
+ $this->_setActiveMenu('report/braintree_transactions');
20
+
21
+ $this->renderLayout();
22
+ }
23
+
24
+ /**
25
+ * Prepare the export into the browser
26
+ *
27
+ * @param string $type
28
+ *
29
+ * @return bool
30
+ */
31
+ private function _prepareExport($type = 'csv')
32
+ {
33
+ // Validate the search query session is set
34
+ if($searchQuery = Mage::getSingleton('adminhtml/session')->getBraintreeSearchQuery()) {
35
+
36
+ // Grab the grid block
37
+ $grid = $this->getLayout()->createBlock('gene_braintree/adminhtml_report_transactions_grid');
38
+
39
+ // Set the search query within the grid
40
+ $grid->setSearchQuery($searchQuery);
41
+
42
+ // Force the file to download in the browser
43
+ $this->_prepareDownloadResponse('braintree-transactions.' . $type, ($type == 'xml' ? $grid->getExcelFile() : $grid->getCsvFile()));
44
+
45
+ return false;
46
+ }
47
+
48
+ // Otherwise take them back
49
+ $this->_redirectReferer();
50
+ }
51
+
52
+ /**
53
+ * Process a request to export the current transactions to a CSV
54
+ */
55
+ public function exportCsvAction()
56
+ {
57
+ return $this->_prepareExport('csv');
58
+ }
59
+
60
+ /**
61
+ * Process a request to export the current transaction to an Excel Document
62
+ */
63
+ public function exportExcelAction()
64
+ {
65
+ return $this->_prepareExport('xml');
66
+ }
67
+
68
+ /**
69
+ * Validate the inputted configuration via Ajax
70
+ */
71
+ public function validateConfigAction()
72
+ {
73
+ // Grab the post data from the request
74
+ $postData = Mage::app()->getRequest()->getPost();
75
+
76
+ // Check the form contains the valid data we need
77
+ if(isset($postData['groups']['gene_braintree']['fields'])) {
78
+
79
+ // Assign it for easy access
80
+ $braintreeConfig = $postData['groups']['gene_braintree']['fields'];
81
+
82
+ // Validate the required variables are set before trying to access them
83
+ if(isset($braintreeConfig['environment']) && isset($braintreeConfig['merchant_id']) && isset($braintreeConfig['public_key']) && isset($braintreeConfig['private_key'])) {
84
+
85
+ // Setup the various configuration variables
86
+ Braintree_Configuration::environment($braintreeConfig['environment']['value']);
87
+ Braintree_Configuration::merchantId($braintreeConfig['merchant_id']['value']);
88
+ Braintree_Configuration::publicKey($braintreeConfig['public_key']['value']);
89
+ Braintree_Configuration::privateKey($braintreeConfig['private_key']['value']);
90
+ }
91
+ }
92
+
93
+ // Do the validation within the wrapper
94
+ Mage::app()->getResponse()->setBody(Mage::getModel('gene_braintree/wrapper_braintree')->validateCredentials(true, true, (isset($braintreeConfig['merchant_account_id']['value']) ? $braintreeConfig['merchant_account_id']['value'] : false)));
95
+ }
96
+
97
+ }
app/code/community/Gene/Braintree/controllers/CheckoutController.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_CheckoutController
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_CheckoutController extends Mage_Core_Controller_Front_Action
9
+ {
10
+ /**
11
+ * The front-end is requesting the grand total of the quote
12
+ */
13
+ public function quoteTotalAction()
14
+ {
15
+ // Grab the quote
16
+ $quote = Mage::getSingleton('checkout/type_onepage')->getQuote();
17
+
18
+ // Build up our JSON response
19
+ $jsonResponse = array(
20
+ 'billingName' => $quote->getBillingAddress()->getName(),
21
+ 'billingPostcode' => $quote->getBillingAddress()->getPostcode(),
22
+ 'grandTotal' => number_format($quote->getGrandTotal(), 2),
23
+ 'currencyCode' => $quote->getQuoteCurrencyCode()
24
+ );
25
+
26
+ // Set the response
27
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($jsonResponse));
28
+ return false;
29
+ }
30
+
31
+ /**
32
+ * Tokenize the card tokens via Ajax
33
+ */
34
+ public function tokenizeCardAction()
35
+ {
36
+ // Are tokens set in the request
37
+ if($tokens = $this->getRequest()->getParam('tokens')) {
38
+
39
+ // Build up our response
40
+ $jsonResponse = array(
41
+ 'success' => true,
42
+ 'tokens' => array()
43
+ );
44
+
45
+ // Json decode the tokens
46
+ $tokens = Mage::helper('core')->jsonDecode($tokens);
47
+ if(is_array($tokens)) {
48
+
49
+ // Loop through each token and tokenize it again
50
+ foreach($tokens as $token) {
51
+ $jsonResponse['tokens'][$token] = Mage::getSingleton('gene_braintree/wrapper_braintree')->getThreeDSecureVaultNonce($token);
52
+ }
53
+
54
+ // Set the response
55
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($jsonResponse));
56
+ return false;
57
+ }
58
+ }
59
+ }
60
+
61
+ }
app/code/community/Gene/Braintree/controllers/SavedController.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Gene_Braintree_SavedController
5
+ *
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ class Gene_Braintree_SavedController extends Mage_Core_Controller_Front_Action
9
+ {
10
+
11
+ /**
12
+ * Retrieve customer session object
13
+ *
14
+ * @return Mage_Customer_Model_Session
15
+ */
16
+ protected function _getSession()
17
+ {
18
+ return Mage::getSingleton('customer/session');
19
+ }
20
+
21
+ /**
22
+ * Validate that the user is logged in
23
+ */
24
+ public function preDispatch()
25
+ {
26
+ parent::preDispatch();
27
+
28
+ if (!Mage::getSingleton('customer/session')->authenticate($this)) {
29
+ $this->setFlag('', 'no-dispatch', true);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Show the listing page of saved payment information
35
+ */
36
+ public function indexAction()
37
+ {
38
+ $this->loadLayout();
39
+
40
+ $this->_initLayoutMessages('customer/session');
41
+ $this->_initLayoutMessages('catalog/session');
42
+
43
+ $this->getLayout()->getBlock('head')->setTitle($this->__('Saved Payment Information'));
44
+
45
+ $this->renderLayout();
46
+ }
47
+
48
+ /**
49
+ * Action to allow users to delete payment methods
50
+ *
51
+ * @return Mage_Core_Controller_Varien_Action
52
+ *
53
+ * @throws Exception
54
+ */
55
+ public function removeAction()
56
+ {
57
+ // Check we've recieved a payment ID
58
+ $token = $this->getRequest()->getParam('id');
59
+ if(!$token) {
60
+ $this->_getSession()->addError('Please select a saved payment entry to remove.');
61
+ return $this->_redirectReferer();
62
+ }
63
+
64
+ // Grab a new instance of the wrapper
65
+ $wrapper = Mage::getModel('gene_braintree/wrapper_braintree');
66
+
67
+ // Init the braintree wrapper
68
+ $wrapper->init();
69
+
70
+ // Load the payment method from Braintree
71
+ try {
72
+ $paymentMethod = Braintree_PaymentMethod::find($token);
73
+ } catch (Exception $e) {
74
+ $this->_getSession()->addError('The requested payment method cannot be found.');
75
+ return $this->_redirectReferer();
76
+ }
77
+
78
+ // Check that this is the users payment method, we have to use a custom method as Braintree don't return the PayPal customer ID
79
+ if(!$wrapper->customerOwnsMethod($paymentMethod)) {
80
+ $this->_getSession()->addError('You do not have permission to modify this payment method.');
81
+ return $this->_redirectReferer();
82
+ }
83
+
84
+ // Remove the payment method
85
+ Braintree_PaymentMethod::delete($token);
86
+
87
+ // Inform the user of the great news
88
+ $this->_getSession()->addSuccess('Saved payment has been successfully deleted.');
89
+ return $this->_redirectReferer();
90
+ }
91
+
92
+ }
app/code/community/Gene/Braintree/etc/adminhtml.xml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <all>
6
+ <title>Allow Everything</title>
7
+ </all>
8
+ <admin>
9
+ <children>
10
+ <report>
11
+ <children>
12
+ <salesroot>
13
+ <children>
14
+ <braintree_transactions translate="title">
15
+ <title>Braintree Transactions</title>
16
+ <sort_order>100</sort_order>
17
+ </braintree_transactions>
18
+ </children>
19
+ </salesroot>
20
+ </children>
21
+ </report>
22
+ </children>
23
+ </admin>
24
+ </resources>
25
+ </acl>
26
+ <menu>
27
+ <report>
28
+ <children>
29
+ <salesroot>
30
+ <children>
31
+ <braintree_transactions translate="title" module="gene_braintree">
32
+ <sort_order>11</sort_order>
33
+ <title>Braintree Transactions</title>
34
+ <action>adminhtml/braintree/transactions</action>
35
+ </braintree_transactions>
36
+ </children>
37
+ </salesroot>
38
+ </children>
39
+ </report>
40
+ </menu>
41
+ </config>
app/code/community/Gene/Braintree/etc/config.xml ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Gene_Braintree>
5
+ <version>1.0.0</version>
6
+ </Gene_Braintree>
7
+ </modules>
8
+ <global>
9
+ <models>
10
+ <gene_braintree>
11
+ <class>Gene_Braintree_Model</class>
12
+ <resourceModel>gene_braintree_resource</resourceModel>
13
+ </gene_braintree>
14
+ <gene_braintree_resource>
15
+ <class>Gene_Braintree_Model_Resource</class>
16
+ </gene_braintree_resource>
17
+ </models>
18
+ <blocks>
19
+ <gene_braintree>
20
+ <class>Gene_Braintree_Block</class>
21
+ </gene_braintree>
22
+
23
+ <checkout>
24
+ <rewrite>
25
+ <cart_totals>Gene_Braintree_Block_Cart_Totals</cart_totals>
26
+ </rewrite>
27
+ </checkout>
28
+ </blocks>
29
+ <helpers>
30
+ <gene_braintree>
31
+ <class>Gene_Braintree_Helper</class>
32
+ </gene_braintree>
33
+ </helpers>
34
+
35
+ <resources>
36
+ <gene_braintree_setup>
37
+ <setup>
38
+ <module>Gene_Braintree</module>
39
+ <class>Mage_Eav_Model_Entity_Setup</class>
40
+ </setup>
41
+ </gene_braintree_setup>
42
+ </resources>
43
+
44
+ <payment>
45
+ <cc>
46
+ <types>
47
+ <ME>
48
+ <code>ME</code>
49
+ <name>Maestro</name>
50
+ <order>10</order>
51
+ </ME>
52
+ </types>
53
+ </cc>
54
+ </payment>
55
+ </global>
56
+
57
+ <!-- Default values for the system configuration pages -->
58
+ <default>
59
+ <payment>
60
+ <!-- Core settings within the module -->
61
+ <gene_braintree>
62
+ <debug>0</debug>
63
+ <multi_currency_enable>0</multi_currency_enable>
64
+ </gene_braintree>
65
+
66
+ <!-- PayPal method -->
67
+ <gene_braintree_paypal>
68
+ <active>0</active>
69
+ <model>gene_braintree/paymentmethod_paypal</model>
70
+ <order_status>processing</order_status>
71
+ <payment_action>authorize_capture</payment_action>
72
+ <title>PayPal (Braintree)</title>
73
+ <environment>sandbox</environment>
74
+ <allowspecific>0</allowspecific>
75
+ <payment_type>single</payment_type>
76
+ <use_vault>0</use_vault>
77
+ <locale>en_gb</locale>
78
+ </gene_braintree_paypal>
79
+
80
+ <!-- Credit Card method -->
81
+ <gene_braintree_creditcard>
82
+ <active>0</active>
83
+ <model>gene_braintree/paymentmethod_creditcard</model>
84
+ <order_status>processing</order_status>
85
+ <payment_action>authorize</payment_action>
86
+ <title>Credit Card (Braintree)</title>
87
+ <environment>sandbox</environment>
88
+ <allowspecific>0</allowspecific>
89
+ <use_vault>0</use_vault>
90
+ <useccv>1</useccv>
91
+ </gene_braintree_creditcard>
92
+
93
+ </payment>
94
+ </default>
95
+
96
+ <frontend>
97
+ <layout>
98
+ <updates>
99
+ <gene_braintree module="Gene_Braintree">
100
+ <file>gene/braintree.xml</file>
101
+ </gene_braintree>
102
+ </updates>
103
+ </layout>
104
+
105
+ <routers>
106
+ <braintree>
107
+ <use>standard</use>
108
+ <args>
109
+ <module>Gene_Braintree</module>
110
+ <frontName>braintree</frontName>
111
+ </args>
112
+ </braintree>
113
+ </routers>
114
+
115
+ <translate>
116
+             <modules>
117
+                 <Gene_Braintree>
118
+                     <files>
119
+                         <default>Gene_Braintree.csv</default>
120
+                     </files>
121
+                 </Gene_Braintree>
122
+             </modules>
123
+         </translate>
124
+
125
+ <events>
126
+ <checkout_submit_all_after>
127
+ <observers>
128
+ <gene_braintree_save_customer_id>
129
+ <type>singleton</type>
130
+ <class>gene_braintree/observer</class>
131
+ <method>completeCheckout</method>
132
+ </gene_braintree_save_customer_id>
133
+ </observers>
134
+ </checkout_submit_all_after>
135
+
136
+ <controller_action_layout_load_before>
137
+ <observers>
138
+ <gene_braintree_detect_checkout>
139
+ <type>singleton</type>
140
+ <class>gene_braintree/observer</class>
141
+ <method>addLayoutHandle</method>
142
+ </gene_braintree_detect_checkout>
143
+ </observers>
144
+ </controller_action_layout_load_before>
145
+ </events>
146
+ </frontend>
147
+
148
+ <adminhtml>
149
+ <layout>
150
+ <updates>
151
+ <gene_braintree>
152
+ <file>gene/braintree.xml</file>
153
+ </gene_braintree>
154
+ </updates>
155
+ </layout>
156
+
157
+ <translate>
158
+             <modules>
159
+                 <Gene_Braintree>
160
+                     <files>
161
+                         <default>Gene_Braintree.csv</default>
162
+                     </files>
163
+                 </Gene_Braintree>
164
+             </modules>
165
+         </translate>
166
+
167
+ <events>
168
+ <sales_order_shipment_save_after>
169
+ <observers>
170
+ <capture_braintree_payment>
171
+ <class>gene_braintree/observer</class>
172
+ <method>captureBraintreePayment</method>
173
+ </capture_braintree_payment>
174
+ </observers>
175
+ </sales_order_shipment_save_after>
176
+ </events>
177
+ </adminhtml>
178
+
179
+ <admin>
180
+ <routers>
181
+ <adminhtml>
182
+ <args>
183
+ <modules>
184
+ <Gene_Braintree before="Mage_Adminhtml">Gene_Braintree_Adminhtml</Gene_Braintree>
185
+ </modules>
186
+ </args>
187
+ </adminhtml>
188
+ </routers>
189
+ </admin>
190
+
191
+ </config>
app/code/community/Gene/Braintree/etc/system.xml ADDED
@@ -0,0 +1,500 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <payment>
5
+ <groups>
6
+ <gene_braintree translate="label comment" module="gene_braintree">
7
+ <label>Braintree v.zero - Configuration</label>
8
+ <sort_order>1498</sort_order>
9
+ <show_in_default>1</show_in_default>
10
+ <show_in_website>1</show_in_website>
11
+ <show_in_store>1</show_in_store>
12
+ <comment><![CDATA[<img src="https://i.imgur.com/JR1BJTr.png" style="margin: 4px 0 8px 0;" border="0"/><br />To use this module you will need an existing production or sandbox Braintree account. You can apply at <a href="https://www.braintreepayments.com">braintreepayments.com</a>.<br />Braintree v.zero integration provided by <a href="http://gene.co.uk/" target="_blank">Gene Commerce</a>.]]></comment>
13
+ <fields>
14
+
15
+ <module_version translate="label">
16
+ <label>Magento Braintree v.zero Version</label>
17
+ <frontend_model>gene_braintree/adminhtml_system_config_braintree_moduleversion</frontend_model>
18
+ <sort_order>20</sort_order>
19
+ <show_in_default>1</show_in_default>
20
+ <show_in_website>1</show_in_website>
21
+ <show_in_store>1</show_in_store>
22
+ </module_version>
23
+
24
+ <lib_version translate="label">
25
+ <label>Braintree PHP SDK Version</label>
26
+ <frontend_model>gene_braintree/adminhtml_system_config_braintree_version</frontend_model>
27
+ <sort_order>20</sort_order>
28
+ <show_in_default>1</show_in_default>
29
+ <show_in_website>1</show_in_website>
30
+ <show_in_store>1</show_in_store>
31
+ </lib_version>
32
+
33
+ <braintree_details translate="label">
34
+ <label>Braintree Account Details</label>
35
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
36
+ <sort_order>30</sort_order>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>1</show_in_store>
40
+ </braintree_details>
41
+
42
+ <environment translate="label comment">
43
+ <label>Environment</label>
44
+ <frontend_type>select</frontend_type>
45
+ <source_model>gene_braintree/source_environment</source_model>
46
+ <sort_order>31</sort_order>
47
+ <show_in_default>1</show_in_default>
48
+ <show_in_website>1</show_in_website>
49
+ <show_in_store>0</show_in_store>
50
+ <comment><![CDATA[
51
+ <strong>Warning:</strong> Do not use 'Sandbox' on a production environment.<br />
52
+ Your API details above will need to reflect your Sandbox or your Production account.
53
+ ]]></comment>
54
+ <frontend_class>validate-config</frontend_class>
55
+ </environment>
56
+
57
+ <merchant_id translate="label">
58
+ <label>Merchant ID</label>
59
+ <frontend_type>text</frontend_type>
60
+ <sort_order>35</sort_order>
61
+ <show_in_default>1</show_in_default>
62
+ <show_in_website>1</show_in_website>
63
+ <show_in_store>0</show_in_store>
64
+ <frontend_class>validate-config</frontend_class>
65
+ </merchant_id>
66
+
67
+ <merchant_account_id translate="label">
68
+ <label>Merchant Account ID</label>
69
+ <frontend_type>text</frontend_type>
70
+ <sort_order>40</sort_order>
71
+ <show_in_default>1</show_in_default>
72
+ <show_in_website>1</show_in_website>
73
+ <show_in_store>1</show_in_store>
74
+ <frontend_class>validate-config</frontend_class>
75
+ <comment><![CDATA[
76
+ If you're accepting different currencies across multiple store views/websites you'll need to adjust your merchant account ID in the correct scope, if you're using the Magento currency switcher you'll need to enable the section below.
77
+ ]]></comment>
78
+ </merchant_account_id>
79
+
80
+ <public_key translate="label">
81
+ <label>Public Key</label>
82
+ <frontend_type>text</frontend_type>
83
+ <sort_order>45</sort_order>
84
+ <show_in_default>1</show_in_default>
85
+ <show_in_website>1</show_in_website>
86
+ <show_in_store>0</show_in_store>
87
+ <frontend_class>validate-config</frontend_class>
88
+ </public_key>
89
+
90
+ <private_key translate="label">
91
+ <label>Private Key</label>
92
+ <frontend_type>text</frontend_type>
93
+ <sort_order>50</sort_order>
94
+ <show_in_default>1</show_in_default>
95
+ <show_in_website>1</show_in_website>
96
+ <show_in_store>0</show_in_store>
97
+ <frontend_class>validate-config</frontend_class>
98
+ </private_key>
99
+
100
+ <valid_config translate="label">
101
+ <label />
102
+ <frontend_model>gene_braintree/adminhtml_system_config_braintree_config</frontend_model>
103
+ <sort_order>55</sort_order>
104
+ <show_in_default>1</show_in_default>
105
+ <show_in_website>1</show_in_website>
106
+ <show_in_store>0</show_in_store>
107
+ </valid_config>
108
+
109
+ <multi_currency_heading translate="label">
110
+ <label>Currency Switcher</label>
111
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
112
+ <sort_order>60</sort_order>
113
+ <show_in_default>1</show_in_default>
114
+ <show_in_website>1</show_in_website>
115
+ <show_in_store>0</show_in_store>
116
+ </multi_currency_heading>
117
+
118
+ <multi_currency_enable>
119
+ <label>Enabled?</label>
120
+ <frontend_type>select</frontend_type>
121
+ <source_model>adminhtml/system_config_source_yesno</source_model>
122
+ <sort_order>65</sort_order>
123
+ <show_in_default>1</show_in_default>
124
+ <show_in_website>1</show_in_website>
125
+ <show_in_store>0</show_in_store>
126
+ <comment><![CDATA[
127
+ If you're using the Magento built in currency switcher you'll need to activate this section to ensure the customers payment goes into your correct merchant account. If you use store views for separate countries you do not need this feature enabled. <br /><strong>Note:</strong> The invoices will still show up as your base currency, but the customer will be charged in their selected currency for the correct amount.
128
+ ]]></comment>
129
+ </multi_currency_enable>
130
+
131
+ <multi_currency_mapping translate="label">
132
+ <label>Mapping</label>
133
+ <backend_model>gene_braintree/system_config_backend_currency</backend_model>
134
+ <frontend_model>gene_braintree/adminhtml_system_config_braintree_currency</frontend_model>
135
+ <sort_order>70</sort_order>
136
+ <show_in_default>1</show_in_default>
137
+ <show_in_website>1</show_in_website>
138
+ <show_in_store>0</show_in_store>
139
+ <depends>
140
+ <multi_currency_enable>1</multi_currency_enable>
141
+ </depends>
142
+ <comment><![CDATA[
143
+ You need to supply each merchant account ID for each enabled currency.
144
+ ]]></comment>
145
+ </multi_currency_mapping>
146
+
147
+ <settings translate="label">
148
+ <label>Testing Settings</label>
149
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
150
+ <sort_order>80</sort_order>
151
+ <show_in_default>1</show_in_default>
152
+ <show_in_website>1</show_in_website>
153
+ <show_in_store>1</show_in_store>
154
+ </settings>
155
+
156
+ <debug translate="label comment">
157
+ <label>Debug</label>
158
+ <frontend_type>select</frontend_type>
159
+ <source_model>adminhtml/system_config_source_yesno</source_model>
160
+ <sort_order>85</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>1</show_in_website>
163
+ <show_in_store>1</show_in_store>
164
+ <comment><![CDATA[
165
+ Debugging will cause a log to be written to the <strong>var/log/gene_braintree.log</strong> file. As no credit card data ever hits the server this file will never contain any crucial customer information.
166
+ ]]></comment>
167
+ </debug>
168
+
169
+ </fields>
170
+ </gene_braintree>
171
+
172
+ <gene_braintree_paypal translate="label comment" module="gene_braintree">
173
+ <label>Braintree v.zero - PayPal</label>
174
+ <sort_order>1499</sort_order>
175
+ <show_in_default>1</show_in_default>
176
+ <show_in_website>1</show_in_website>
177
+ <show_in_store>1</show_in_store>
178
+ <comment><![CDATA[<img src="https://i.imgur.com/sitDbHA.png" style="margin: 6px 0;" /><br />You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details.]]></comment>
179
+ <fields>
180
+
181
+ <active translate="label">
182
+ <label>Enabled</label>
183
+ <frontend_type>select</frontend_type>
184
+ <source_model>adminhtml/system_config_source_yesno</source_model>
185
+ <sort_order>1</sort_order>
186
+ <show_in_default>1</show_in_default>
187
+ <show_in_website>1</show_in_website>
188
+ <show_in_store>0</show_in_store>
189
+ </active>
190
+
191
+ <title translate="label">
192
+ <label>Title</label>
193
+ <frontend_type>text</frontend_type>
194
+ <sort_order>2</sort_order>
195
+ <show_in_default>1</show_in_default>
196
+ <show_in_website>1</show_in_website>
197
+ <show_in_store>1</show_in_store>
198
+ </title>
199
+
200
+ <capture_heading translate="label">
201
+ <label>Capture</label>
202
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
203
+ <sort_order>5</sort_order>
204
+ <show_in_default>1</show_in_default>
205
+ <show_in_website>1</show_in_website>
206
+ <show_in_store>1</show_in_store>
207
+ </capture_heading>
208
+
209
+ <order_status translate="label">
210
+ <label>Complete Order Status</label>
211
+ <frontend_type>select</frontend_type>
212
+ <source_model>adminhtml/system_config_source_order_status_processing</source_model>
213
+ <sort_order>10</sort_order>
214
+ <show_in_default>1</show_in_default>
215
+ <show_in_website>1</show_in_website>
216
+ <show_in_store>1</show_in_store>
217
+ </order_status>
218
+
219
+ <features_heading translate="label">
220
+ <label>Features</label>
221
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
222
+ <sort_order>70</sort_order>
223
+ <show_in_default>1</show_in_default>
224
+ <show_in_website>1</show_in_website>
225
+ <show_in_store>1</show_in_store>
226
+ </features_heading>
227
+
228
+ <payment_type translate="label comment">
229
+ <label>Payment Type</label>
230
+ <frontend_type>select</frontend_type>
231
+ <source_model>gene_braintree/source_paypal_paymenttype</source_model>
232
+ <sort_order>75</sort_order>
233
+ <show_in_default>1</show_in_default>
234
+ <show_in_website>1</show_in_website>
235
+ <show_in_store>1</show_in_store>
236
+ <comment><![CDATA[
237
+ <strong>Single Payment</strong> - Will only require the customer to sign in, we will only be able to take a single payment<br />
238
+ <strong>Future Payments</strong> - Allows us to save the customers PayPal account for later purchases and use with the Vault
239
+ ]]></comment>
240
+ </payment_type>
241
+
242
+ <locale translate="label comment">
243
+ <label>Locale</label>
244
+ <frontend_type>select</frontend_type>
245
+ <source_model>gene_braintree/source_paypal_locale</source_model>
246
+ <sort_order>80</sort_order>
247
+ <show_in_default>1</show_in_default>
248
+ <show_in_website>1</show_in_website>
249
+ <show_in_store>1</show_in_store>
250
+ <depends>
251
+ <payment_type>single</payment_type>
252
+ </depends>
253
+ <comment><![CDATA[
254
+ The locale for the PayPal popup window
255
+ ]]></comment>
256
+ </locale>
257
+
258
+ <use_vault translate="label comment">
259
+ <label>Enable Vault</label>
260
+ <frontend_type>select</frontend_type>
261
+ <source_model>adminhtml/system_config_source_yesno</source_model>
262
+ <sort_order>80</sort_order>
263
+ <show_in_default>1</show_in_default>
264
+ <show_in_website>1</show_in_website>
265
+ <show_in_store>1</show_in_store>
266
+ <depends>
267
+ <payment_type>future</payment_type>
268
+ </depends>
269
+ <comment><![CDATA[
270
+ Storing the customers PayPal in the vault will allow them to instantly purchase any product without having to login to PayPal again.
271
+ ]]></comment>
272
+ </use_vault>
273
+
274
+ <display_heading translate="label">
275
+ <label>Display</label>
276
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
277
+ <sort_order>100</sort_order>
278
+ <show_in_default>1</show_in_default>
279
+ <show_in_website>1</show_in_website>
280
+ <show_in_store>1</show_in_store>
281
+ </display_heading>
282
+
283
+ <sort_order translate="label">
284
+ <label>Sort Order</label>
285
+ <frontend_type>text</frontend_type>
286
+ <sort_order>150</sort_order>
287
+ <show_in_default>1</show_in_default>
288
+ <show_in_website>1</show_in_website>
289
+ <show_in_store>1</show_in_store>
290
+ </sort_order>
291
+
292
+ </fields>
293
+ </gene_braintree_paypal>
294
+
295
+ <gene_braintree_creditcard translate="label comment" module="gene_braintree">
296
+ <label>Braintree v.zero - Credit Card</label>
297
+ <sort_order>1500</sort_order>
298
+ <show_in_default>1</show_in_default>
299
+ <show_in_website>1</show_in_website>
300
+ <show_in_store>1</show_in_store>
301
+ <comment><![CDATA[You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details.]]></comment>
302
+ <fields>
303
+
304
+ <active translate="label">
305
+ <label>Enabled</label>
306
+ <frontend_type>select</frontend_type>
307
+ <source_model>adminhtml/system_config_source_yesno</source_model>
308
+ <sort_order>1</sort_order>
309
+ <show_in_default>1</show_in_default>
310
+ <show_in_website>1</show_in_website>
311
+ <show_in_store>0</show_in_store>
312
+ </active>
313
+
314
+ <title translate="label">
315
+ <label>Title</label>
316
+ <frontend_type>text</frontend_type>
317
+ <sort_order>2</sort_order>
318
+ <show_in_default>1</show_in_default>
319
+ <show_in_website>1</show_in_website>
320
+ <show_in_store>1</show_in_store>
321
+ </title>
322
+
323
+ <capture_heading translate="label">
324
+ <label>Capture</label>
325
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
326
+ <sort_order>5</sort_order>
327
+ <show_in_default>1</show_in_default>
328
+ <show_in_website>1</show_in_website>
329
+ <show_in_store>1</show_in_store>
330
+ </capture_heading>
331
+
332
+ <payment_action translate="label comment">
333
+ <label>Payment Action</label>
334
+ <frontend_type>select</frontend_type>
335
+ <source_model>gene_braintree/source_creditcard_paymentAction</source_model>
336
+ <sort_order>9</sort_order>
337
+ <show_in_default>1</show_in_default>
338
+ <show_in_website>1</show_in_website>
339
+ <show_in_store>0</show_in_store>
340
+ <comment><![CDATA[
341
+ <strong>Authorize</strong> - Will only auth the payment and store a token, the transaction will not be settled.<br />
342
+ <strong>Authorize & Capture</strong> - We will instantly settle the transaction within the checkout.
343
+ ]]></comment>
344
+ </payment_action>
345
+
346
+ <capture_action translate="label comment">
347
+ <label>Capture Action</label>
348
+ <frontend_type>select</frontend_type>
349
+ <source_model>gene_braintree/source_creditcard_captureAction</source_model>
350
+ <sort_order>10</sort_order>
351
+ <show_in_default>1</show_in_default>
352
+ <show_in_website>1</show_in_website>
353
+ <show_in_store>0</show_in_store>
354
+ <comment><![CDATA[
355
+ If you're just authorizing transactions you can define at what point they should be submitted for settlement.
356
+ ]]></comment>
357
+ <depends>
358
+ <payment_action>authorize</payment_action>
359
+ </depends>
360
+ </capture_action>
361
+
362
+ <order_status translate="label">
363
+ <label>New Order Status</label>
364
+ <frontend_type>select</frontend_type>
365
+ <source_model>adminhtml/system_config_source_order_status_processing</source_model>
366
+ <sort_order>20</sort_order>
367
+ <show_in_default>1</show_in_default>
368
+ <show_in_website>1</show_in_website>
369
+ <show_in_store>1</show_in_store>
370
+ </order_status>
371
+
372
+ <features_heading translate="label">
373
+ <label>Features</label>
374
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
375
+ <sort_order>70</sort_order>
376
+ <show_in_default>1</show_in_default>
377
+ <show_in_website>1</show_in_website>
378
+ <show_in_store>1</show_in_store>
379
+ </features_heading>
380
+
381
+ <use_vault translate="label comment">
382
+ <label>Enable Vault/Saved Cards</label>
383
+ <frontend_type>select</frontend_type>
384
+ <source_model>adminhtml/system_config_source_yesno</source_model>
385
+ <sort_order>75</sort_order>
386
+ <show_in_default>1</show_in_default>
387
+ <show_in_website>1</show_in_website>
388
+ <show_in_store>1</show_in_store>
389
+ <comment><![CDATA[
390
+ The vault allows you to securely store the customers credit card on Braintree's servers. We're provided with a token which allows the customer to make future payments without having to enter any details again.
391
+ ]]></comment>
392
+ </use_vault>
393
+
394
+ <threedsecure translate="label comment">
395
+ <label>Enable 3D Secure</label>
396
+ <frontend_type>select</frontend_type>
397
+ <source_model>adminhtml/system_config_source_yesno</source_model>
398
+ <sort_order>76</sort_order>
399
+ <show_in_default>1</show_in_default>
400
+ <show_in_website>1</show_in_website>
401
+ <show_in_store>1</show_in_store>
402
+ <comment><![CDATA[
403
+ The 3D Secure feature enables the shopper to enter a password to confirm their identity with the card issuer. If accepted they then complete their order, and when received by you, you have much more confidence that is genuine and real.
404
+ ]]></comment>
405
+ </threedsecure>
406
+
407
+ <useccv translate="label comment">
408
+ <label>CVV Verification</label>
409
+ <frontend_type>select</frontend_type>
410
+ <source_model>adminhtml/system_config_source_yesno</source_model>
411
+ <sort_order>76</sort_order>
412
+ <show_in_default>1</show_in_default>
413
+ <show_in_website>1</show_in_website>
414
+ <show_in_store>1</show_in_store>
415
+ <comment><![CDATA[
416
+ Should we verify the CVV against the card?
417
+ ]]></comment>
418
+ </useccv>
419
+
420
+ <kount_merchant_id translate="label comment">
421
+ <label>Kount Merchant ID</label>
422
+ <frontend_type>text</frontend_type>
423
+ <sort_order>78</sort_order>
424
+ <show_in_default>1</show_in_default>
425
+ <show_in_website>1</show_in_website>
426
+ <show_in_store>1</show_in_store>
427
+ <comment><![CDATA[
428
+ Braintree offers a direct integration with Kount, our partner for providing advanced fraud detection technology. To use this feature, you must be processing at least 2500 transactions per month, and you’ll be subject to additional fees from Kount for their services. To get started, contact accounts@braintreepayments.com. You can view more information <a href="https://developers.braintreepayments.com/javascript+php/guides/fraud-tools">here</a>.
429
+ ]]></comment>
430
+ </kount_merchant_id>
431
+
432
+ <cctypes translate="label">
433
+ <label>Credit Card Types</label>
434
+ <frontend_type>multiselect</frontend_type>
435
+ <source_model>gene_braintree/source_cctype</source_model>
436
+ <sort_order>85</sort_order>
437
+ <show_in_default>1</show_in_default>
438
+ <show_in_website>1</show_in_website>
439
+ <show_in_store>0</show_in_store>
440
+ </cctypes>
441
+
442
+ <allowspecific translate="label">
443
+ <label>Payment from Applicable Countries</label>
444
+ <frontend_type>allowspecific</frontend_type>
445
+ <sort_order>90</sort_order>
446
+ <source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>
447
+ <show_in_default>1</show_in_default>
448
+ <show_in_website>1</show_in_website>
449
+ <show_in_store>0</show_in_store>
450
+ </allowspecific>
451
+
452
+ <specificcountry translate="label">
453
+ <label>Payment from Specific Countries</label>
454
+ <frontend_type>multiselect</frontend_type>
455
+ <sort_order>95</sort_order>
456
+ <source_model>adminhtml/system_config_source_country</source_model>
457
+ <show_in_default>1</show_in_default>
458
+ <show_in_website>1</show_in_website>
459
+ <show_in_store>0</show_in_store>
460
+ </specificcountry>
461
+
462
+ <!-- @todo to be included in a future release -->
463
+ <!--<dynamic_descriptors translate="label comment">-->
464
+ <!--<label>Dynamic Descriptors</label>-->
465
+ <!--<frontend_type>select</frontend_type>-->
466
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
467
+ <!--<sort_order>100</sort_order>-->
468
+ <!--<show_in_default>1</show_in_default>-->
469
+ <!--<show_in_website>1</show_in_website>-->
470
+ <!--<show_in_store>0</show_in_store>-->
471
+ <!--<comment><![CDATA[-->
472
+ <!--Dyanmic descriptors allow you to modify the entry shown on the customers statement. This will include the company name, company phone number and the company URL.<br />-->
473
+ <!--<strong>Note:</strong> You must have this enabled on your account, you can find out more information <a href="https://developers.braintreepayments.com/javascript+php/sdk/server/transaction-processing/dynamic-descriptors">here</a>.-->
474
+ <!--]]></comment>-->
475
+ <!--</dynamic_descriptors>-->
476
+
477
+ <display_heading translate="label">
478
+ <label>Display</label>
479
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
480
+ <sort_order>145</sort_order>
481
+ <show_in_default>1</show_in_default>
482
+ <show_in_website>1</show_in_website>
483
+ <show_in_store>1</show_in_store>
484
+ </display_heading>
485
+
486
+ <sort_order translate="label">
487
+ <label>Sort Order</label>
488
+ <frontend_type>text</frontend_type>
489
+ <sort_order>150</sort_order>
490
+ <show_in_default>1</show_in_default>
491
+ <show_in_website>1</show_in_website>
492
+ <show_in_store>1</show_in_store>
493
+ </sort_order>
494
+
495
+ </fields>
496
+ </gene_braintree_creditcard>
497
+ </groups>
498
+ </payment>
499
+ </sections>
500
+ </config>
app/code/community/Gene/Braintree/sql/gene_braintree_setup/install-0.1.0.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+ $installer->startSetup();
5
+
6
+ $entityTypeId = $installer->getEntityTypeId('customer');
7
+ $attributeSetId = $installer->getDefaultAttributeSetId($entityTypeId);
8
+ $attributeGroupId = $installer->getDefaultAttributeGroupId($entityTypeId, $attributeSetId);
9
+
10
+ // Add in a new attribute for the braintree's customer ID
11
+ // This is generated and stored Magento side and is used for stored details
12
+ $installer->addAttribute('customer', 'braintree_customer_id', array(
13
+ 'input' => 'text',
14
+ 'type' => 'varchar',
15
+ 'label' => 'Generated Braintree Customer Account ID',
16
+ 'visible' => 0,
17
+ 'required' => 0,
18
+ 'user_defined' => 1,
19
+ ));
20
+
21
+ // Add the attribute into the group
22
+ $installer->addAttributeToGroup(
23
+ $entityTypeId,
24
+ $attributeSetId,
25
+ $attributeGroupId,
26
+ 'braintree_customer_id',
27
+ '999'
28
+ );
29
+
30
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/gene/braintree.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+
4
+ <adminhtml_braintree_transactions>
5
+ <reference name="content">
6
+ <block type="gene_braintree/adminhtml_report_transactions" name="gene.braintree.report.transactions"
7
+ template="gene/braintree/transactions/index.phtml">
8
+ <block type="gene_braintree/adminhtml_report_transactions_search"
9
+ name="gene.braintree.report.transactions.search" as="search"
10
+ template="gene/braintree/transactions/search.phtml"/>
11
+ </block>
12
+ </reference>
13
+ </adminhtml_braintree_transactions>
14
+
15
+ <adminhtml_sales_order_create_index>
16
+ <reference name="head">
17
+ <action method="addJs"><file>gene/braintree/braintree.js</file></action>
18
+ <action method="addJs"><file>gene/braintree/vzero.js</file></action>
19
+ </reference>
20
+ <reference name="before_body_end">
21
+ <block type="gene_braintree/js" name="gene_braintree_js" template="gene/braintree/js.phtml" />
22
+ </reference>
23
+ </adminhtml_sales_order_create_index>
24
+
25
+ </layout>
app/design/adminhtml/default/default/template/gene/braintree/creditcard.phtml ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Gene_Braintree_Block_Creditcard */
3
+ $_code = $this->getMethodCode()
4
+ ?>
5
+ <div id="payment_form_<?php echo $_code ?>" style="display:none;" class="form-list">
6
+
7
+ <div id="credit-card-form">
8
+ <ul class="form-list">
9
+ <li>
10
+ <div class="input-box">
11
+ <label for="<?php echo $_code ?>_cc_type"><?php echo Mage::helper('payment')->__('Credit Card Type') ?> <span class="required">*</span></label><br/>
12
+ <select id="<?php echo $_code ?>_cc_type" name="payment[cc_type]" class="required-entry validate-cc-type-select">
13
+ <?php $_ccType = $this->getInfoData('cc_type') ?>
14
+ <option value=""></option>
15
+ <?php foreach ($this->getOriginalCcAvailableTypes() as $_typeCode => $_typeName): ?>
16
+ <option value="<?php echo $_typeCode ?>" <?php if($_typeCode==$_ccType): ?>selected="selected"<?php endif ?>><?php echo $_typeName ?></option>
17
+ <?php endforeach ?>
18
+ </select>
19
+ </div>
20
+ </li>
21
+ <li>
22
+ <div class="input-box">
23
+ <label for="<?php echo $_code ?>_cc_number"><?php echo Mage::helper('payment')->__('Credit Card Number') ?> <span class="required">*</span></label><br/>
24
+ <input type="text" data-genebraintree-name="number" name="payment[cc_number]" id="<?php echo $_code ?>_cc_number" title="<?php echo $this->__('Credit Card Number') ?>" class="input-text validate-cc-number validate-cc-type" value=""/>
25
+ </div>
26
+ </li>
27
+ <li>
28
+ <div class="input-box">
29
+ <label for="<?php echo $_code ?>_expiration"><?php echo Mage::helper('payment')->__('Expiration Date') ?> <span class="required">*</span></label><br/>
30
+ <select id="<?php echo $_code ?>_expiration" name="payment[cc_exp_month]" data-genebraintree-name="expiration_month" class="validate-cc-exp required-entry">
31
+ <?php $_ccExpMonth = $this->getInfoData('cc_exp_month') ?>
32
+ <?php foreach ($this->getCcMonths() as $k=>$v): ?>
33
+ <option value="<?php echo $k ?>" <?php if($k==$_ccExpMonth): ?>selected="selected"<?php endif ?>><?php echo $v ?></option>
34
+ <?php endforeach ?>
35
+ </select>
36
+ <?php $_ccExpYear = $this->getInfoData('cc_exp_year') ?>
37
+ <select id="<?php echo $_code ?>_expiration_yr" name="payment[cc_exp_year]" data-genebraintree-name="expiration_year" class="required-entry">
38
+ <?php foreach ($this->getCcYears() as $k=>$v): ?>
39
+ <option value="<?php echo $k ? $k : '' ?>" <?php if($k==$_ccExpYear): ?>selected="selected"<?php endif ?>><?php echo $v ?></option>
40
+ <?php endforeach ?>
41
+ </select>
42
+ </div>
43
+ </li>
44
+ <?php echo $this->getChildHtml() ?>
45
+ <?php if($this->hasVerification()): ?>
46
+ <li>
47
+ <div class="input-box">
48
+ <label for="<?php echo $_code ?>_cc_cid"><?php echo Mage::helper('payment')->__('Card Verification Number') ?> <span class="required">*</span></label><br/>
49
+ <input type="text" title="<?php echo $this->__('Card Verification Number') ?>" class="input-text cvv required-entry validate-cc-cvn" id="<?php echo $_code ?>_cc_cid" name="payment[cc_cid]" data-genebraintree-name="cvv" value="" />
50
+ </div>
51
+ </li>
52
+ <?php endif; ?>
53
+
54
+ </ul>
55
+
56
+ <!-- Fields for the payment method -->
57
+ <input type="hidden" name="payment[payment_method_nonce]" id="creditcard-payment-nonce" />
58
+
59
+ <input type="hidden" id="<?php echo $_code ?>_cc_type" value="" />
60
+ </div>
61
+
62
+ </div>
63
+
64
+ <style type="text/css">
65
+ .card-number {
66
+ position: relative;
67
+ }
68
+
69
+ .card-type {
70
+ position: absolute;
71
+ top: 0;
72
+ left: 6px;
73
+ }
74
+
75
+ .card-number input {
76
+ height: 46px;
77
+ text-indent: 54px;
78
+ }
79
+ </style>
80
+
81
+ <script type="text/javascript">
82
+ //<![CDATA[
83
+ Validation.creditCartTypes = $H({
84
+ 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true],
85
+ 'MC': [new RegExp('^5[1-5][0-9]{14}$'), new RegExp('^[0-9]{3}$'), true],
86
+ 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true],
87
+ 'DI': [new RegExp('^6011[0-9]{12}$'), new RegExp('^[0-9]{3}$'), true],
88
+ 'JCB': [new RegExp('^(3[0-9]{15}|(2131|1800)[0-9]{11})$'), new RegExp('^[0-9]{4}$'), true],
89
+ 'OT': [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), false]
90
+ });
91
+ //]]>
92
+ </script>
93
+
94
+ <!-- Attach an event onto all radio buttons -->
95
+ <script type="text/javascript">
96
+
97
+ // Verify that vzero is defined before attempting to use it
98
+ if(typeof vzero !== 'undefined') {
99
+
100
+ // Only needed for 3DS transactions but still helpful
101
+ vzero.setAmount('<?php echo Mage::getSingleton('checkout/cart')->getQuote()->collectTotals()->getGrandTotal(); ?>');
102
+ }
103
+
104
+ // Loop through each saved card being selected
105
+ $$('#creditcard-saved-accounts input[type="radio"]').each(function(elm) {
106
+
107
+ // Observe the elements changing
108
+ Element.observe(elm, 'change', function(event) {
109
+
110
+ // Has the user selected other?
111
+ if($$('#creditcard-saved-accounts input:checked[type=radio]').first().value == 'other') {
112
+
113
+ // Show the credit card form
114
+ $('credit-card-form').show();
115
+
116
+ // Enable the credit card form all the elements in the credit card form
117
+ $$('#credit-card-form input, #credit-card-form select').each(function(formElement) {
118
+ formElement.removeAttribute('disabled');
119
+ });
120
+
121
+ } else {
122
+
123
+ // Hide the new credit card form
124
+ $('credit-card-form').hide();
125
+
126
+ // Disable all the elements in the credit card form
127
+ $$('#credit-card-form input, #credit-card-form select').each(function(formElement) {
128
+ formElement.setAttribute('disabled', 'disabled');
129
+ });
130
+
131
+ }
132
+ });
133
+ });
134
+
135
+ </script>
app/design/adminhtml/default/default/template/gene/braintree/creditcard/info.phtml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div id="braintree_creditcard_logo" style="padding-top: 5px;padding-left: 2px;">
3
+ <img src="http://i.imgur.com/JR1BJTr.png" alt="<?php echo $this->__('PayPal - Braintree'); ?>" /> by <a href="http://gene.co.uk" target="_blank" style="text-decoration: none;">Gene Commerce</a>
4
+ </div>
5
+
6
+ <?php if ($_specificInfo = $this->getSpecificInformation()):?>
7
+ <table>
8
+ <?php foreach ($_specificInfo as $_label => $_value):?>
9
+ <tr>
10
+ <th width="220"><?php echo $this->escapeHtml($_label)?>:</td>
11
+ <td><?php echo nl2br(implode($this->getValueAsArray($_value, false), "\n"))?></td>
12
+ </tr>
13
+ <?php endforeach; ?>
14
+ </table>
15
+ <?php endif;?>
16
+
17
+ <?php echo $this->getChildHtml()?>
app/design/adminhtml/default/default/template/gene/braintree/js.phtml ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script type="text/javascript">
2
+ //<![CDATA[
3
+ // Pass some data over to vZero integration JS
4
+ var vzero = new vZero(
5
+ 'gene_braintree_creditcard',
6
+ '<?php echo $this->getClientToken(); ?>',
7
+ false,
8
+ ['order-billing_address_firstname', 'order-billing_address_lastname'],
9
+ ['order-billing_address_postcode']
10
+ );
11
+
12
+ // Init the environment
13
+ vzero.init();
14
+
15
+ // Store the original payment method
16
+ var adminOrderOriginal = AdminOrder.prototype.submit;
17
+
18
+ // Intercept the save function
19
+ AdminOrder.prototype.submit = function() {
20
+
21
+ // Check we're using the braintree card method
22
+ if(order.paymentMethod == 'gene_braintree_creditcard') {
23
+
24
+ // Validate the form contents
25
+ if (editForm.validate()) {
26
+
27
+ // Store these to be used later on
28
+ var adminThis = this;
29
+ var adminArgs = arguments;
30
+
31
+ // Process the card
32
+ vzero.process({
33
+ onSuccess: function () {
34
+
35
+ // Disable the standard credit card form so the values don't get passed through to the checkout
36
+ $$('#payment_form_gene_braintree_creditcard input, #payment_form_gene_braintree_creditcard select').each(function (formElement) {
37
+ if (formElement.id != 'creditcard-payment-nonce' && formElement.getAttribute('data-genebraintree-name') != 'cvv' && formElement.id != 'gene_braintree_creditcard_store_in_vault' && formElement.id != 'device_data') {
38
+ formElement.setAttribute('disabled', 'disabled');
39
+ }
40
+ });
41
+
42
+ // Fire the original event and return the response
43
+ adminOrderResponse = adminOrderOriginal.apply(adminThis, adminArgs);
44
+
45
+ // Re-enable any form elements which were disabled
46
+ $$('#payment_form_gene_braintree_creditcard input, #payment_form_gene_braintree_creditcard select').each(function (formElement) {
47
+ formElement.removeAttribute('disabled');
48
+ });
49
+
50
+ // Run the original function
51
+ return adminOrderResponse;
52
+
53
+ }
54
+ });
55
+ }
56
+
57
+ } else {
58
+ return adminOrderOriginal.apply(this, arguments);
59
+ }
60
+
61
+ };
62
+ //]]>
63
+ </script>
app/design/adminhtml/default/default/template/gene/braintree/paypal/info.phtml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div id="braintree_paypal_logo" style="padding-top: 5px;padding-left: 2px;">
3
+ <img src="http://i.imgur.com/sitDbHA.png" alt="<?php echo $this->__('PayPal - Braintree'); ?>" /> by <a href="http://gene.co.uk" target="_blank" style="text-decoration: none;">Gene Commerce</a>
4
+ </div>
5
+
6
+ <?php if ($_specificInfo = $this->getSpecificInformation()):?>
7
+ <table>
8
+ <?php foreach ($_specificInfo as $_label => $_value):?>
9
+ <tr>
10
+ <th width="180"><?php echo $this->escapeHtml($_label)?>:</td>
11
+ <td><?php echo nl2br(implode($this->getValueAsArray($_value, true), "\n"))?></td>
12
+ </tr>
13
+ <?php endforeach; ?>
14
+ </table>
15
+ <?php endif;?>
16
+
17
+ <?php echo $this->getChildHtml()?>
app/design/adminhtml/default/default/template/gene/braintree/transactions/index.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="content-header">
2
+ <table cellspacing="0">
3
+ <tr>
4
+ <td style="<?php echo $this->getHeaderWidth() ?>"><?php echo $this->getHeaderHtml() ?></td>
5
+ <td class="form-buttons"><?php echo $this->getButtonsHtml() ?></td>
6
+ </tr>
7
+ </table>
8
+ </div>
9
+ <?php echo $this->getChildHtml('search'); ?>
10
+ <div>
11
+ <?php echo $this->getGridHtml() ?>
12
+ </div>
app/design/adminhtml/default/default/template/gene/braintree/transactions/search.phtml ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <form action="" method="get">
2
+ <div class="switcher search">
3
+
4
+ <table>
5
+ <tr>
6
+ <th><label class="date_label" style="font-weight: bold;"><?php echo $this->__('Date Filter:') ?></label></th>
7
+ <td>
8
+ <span class="label"><?php echo $this->__('From:'); ?></span>
9
+ <img src="<?php echo $this->getSkinUrl('images/grid-cal.gif'); ?>" alt="" class="v-middle" id="gene_braintree_from_date_trig" title="Date selector">
10
+ <input type="text" name="from_date" id="gene_braintree_from_date" class="input-text no-changes" value="<?php echo $this->getFromDate(); ?>" size="14">
11
+
12
+ <span class="label"><?php echo $this->__('To:'); ?></span>
13
+ <img src="<?php echo $this->getSkinUrl('images/grid-cal.gif'); ?>" alt="" class="v-middle" id="gene_braintree_to_date_trig" title="Date selector">
14
+ <input type="text" name="to_date" id="gene_braintree_to_date" class="input-text no-changes" value="<?php echo $this->getToDate(); ?>" size="14">
15
+ </td>
16
+ </tr>
17
+ <tr>
18
+ <th><label style="font-weight: bold;" for="braintree_type"><?php echo $this->__('Type:') ?></label></th>
19
+ <td>
20
+ <select id="braintree_type" name="type">
21
+ <?php foreach($this->getTypesAsArray() as $key => $value): ?>
22
+ <option value="<?php echo $key; ?>"<?php echo ($this->getSelectedType() == $key ? ' selected="selected"' : ''); ?>><?php echo $value; ?></option>
23
+ <?php endforeach; ?>
24
+ </select>
25
+ </td>
26
+ </tr>
27
+ <tr>
28
+ <th><label style="font-weight: bold;" for="braintree_status"><?php echo $this->__('Status:') ?></label></th>
29
+ <td>
30
+ <select id="braintree_status" name="status">
31
+ <?php foreach($this->getStatusesAsArray() as $key => $value): ?>
32
+ <option value="<?php echo $key; ?>"<?php echo ($this->getSelectedStatus() == $key ? ' selected="selected"' : ''); ?>><?php echo $value; ?></option>
33
+ <?php endforeach; ?>
34
+ </select>
35
+ </td>
36
+ </tr>
37
+ <tr>
38
+ <th><label style="font-weight: bold;" for="braintree_order_id"><?php echo $this->__('Magento Order ID:') ?></label></th>
39
+ <td>
40
+ <input type="text" id="braintree_order_id" name="order_id" value="<?php echo $this->getOrderId(); ?>" class="input-text" />
41
+ </td>
42
+ </tr>
43
+ <tr>
44
+ <th colspan="2">
45
+ <button type="submit">Filter Transactions</button>
46
+ <button type="reset" onclick="window.location='<?php echo Mage::helper('adminhtml')->getUrl('*/*/*'); ?>';">Reset</button>
47
+ </th>
48
+ </tr>
49
+ </table>
50
+ </div>
51
+ </form>
52
+
53
+ <style type="text/css">
54
+ .switcher.search th, .switcher.search td {
55
+ padding: 4px 10px 4px 2px;
56
+ }
57
+ </style>
58
+
59
+ <!-- Include the Calender Javascript -->
60
+ <script type="text/javascript">
61
+ Calendar.setup({
62
+ inputField : "gene_braintree_from_date",
63
+ ifFormat : "%d-%m-%Y %H:%M",
64
+ button : "gene_braintree_from_date_trig",
65
+ align : "Bl",
66
+ singleClick : true,
67
+ showsTime: true
68
+ });
69
+ Calendar.setup({
70
+ inputField : "gene_braintree_to_date",
71
+ ifFormat : "%d-%m-%Y %H:%M",
72
+ button : "gene_braintree_to_date_trig",
73
+ align : "Bl",
74
+ singleClick : true,
75
+ showsTime: true
76
+ });
77
+
78
+ $("gene_braintree_from_date_trig").observe("click", showCalendar);
79
+ $("gene_braintree_to_date_trig").observe("click", showCalendar);
80
+
81
+ function showCalendar(event){
82
+ var element = event.element(event);
83
+ var offset = $(element).viewportOffset();
84
+ var scrollOffset = $(element).cumulativeScrollOffset();
85
+ var dimensionsButton = $(element).getDimensions();
86
+ var index = $("widget-chooser").getStyle("zIndex");
87
+
88
+ $$("div.calendar").each(function(item){
89
+ if ($(item).visible()) {
90
+ var dimensionsCalendar = $(item).getDimensions();
91
+
92
+ $(item).setStyle({
93
+ "zIndex" : index + 1,
94
+ "left" : offset[0] + scrollOffset[0] - dimensionsCalendar.width
95
+ + dimensionsButton.width + "px",
96
+ "top" : offset[1] + scrollOffset[1] + dimensionsButton.height + "px"
97
+ });
98
+ };
99
+ });
100
+ };
101
+ </script>
app/design/frontend/base/default/layout/gene/braintree.xml ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+
4
+ <checkout_onepage_index>
5
+ <reference name="head">
6
+ <action method="addJs"><file>gene/braintree/braintree.js</file></action>
7
+ <action method="addJs"><file>gene/braintree/vzero.js</file></action>
8
+ </reference>
9
+ <reference name="before_body_end">
10
+ <block type="gene_braintree/js" name="gene_braintree_setup" template="gene/braintree/js/setup.phtml" />
11
+ <block type="gene_braintree/js" name="gene_braintree_js" template="gene/braintree/js/default.phtml" />
12
+
13
+ <!-- Set the payment form ID for the fraud prevention -->
14
+ <block type="gene_braintree/js" name="gene_braintree_data" template="gene/braintree/js/data.phtml">
15
+ <action method="setData">
16
+ <key>payment_form_id</key>
17
+ <value>co-payment-form</value>
18
+ </action>
19
+ </block>
20
+ </reference>
21
+ </checkout_onepage_index>
22
+
23
+ <!-- We have to use a customized version of the js.phtml file for Amasty's checkout solution -->
24
+ <amasty_onestep_checkout>
25
+ <reference name="before_body_end">
26
+ <remove name="gene_braintree_js" />
27
+ <block type="gene_braintree/js" name="gene_braintree_amasty_js" template="gene/braintree/js/amasty.phtml" />
28
+ </reference>
29
+ </amasty_onestep_checkout>
30
+
31
+ <!-- Need to include the standard resources for the onestepcheckout.com solution -->
32
+ <onestepcheckout_index_index>
33
+ <reference name="head">
34
+ <action method="addJs"><file>gene/braintree/braintree.js</file></action>
35
+ <action method="addJs"><file>gene/braintree/vzero.js</file></action>
36
+ </reference>
37
+ <reference name="before_body_end">
38
+ <block type="gene_braintree/js" name="gene_braintree_setup" template="gene/braintree/js/setup.phtml" />
39
+ <block type="gene_braintree/js" name="gene_braintree_js" template="gene/braintree/js/idev.phtml" />
40
+
41
+ <!-- We include device data at the end of the larger form -->
42
+ <block type="gene_braintree/js" name="gene_braintree_data" template="gene/braintree/js/data.phtml">
43
+ <action method="setData">
44
+ <key>payment_form_id</key>
45
+ <value>onestepcheckout-form</value>
46
+ </action>
47
+ </block>
48
+ </reference>
49
+ </onestepcheckout_index_index>
50
+
51
+ <checkout_onepage_paymentmethod>
52
+ <reference name="root">
53
+ <block type="core/text_list" name="additional" as="additional">
54
+ <block type="gene_braintree/creditcard_threedsecure" name="gene_braintree_creditcard_threedsecure" template="gene/braintree/creditcard/threedsecure.phtml" />
55
+ </block>
56
+ </reference>
57
+ </checkout_onepage_paymentmethod>
58
+
59
+ <customer_account>
60
+ <reference name="customer_account_navigation">
61
+ <action method="addLink" translate="label" module="customer">
62
+ <name>braintree.saved</name>
63
+ <path>braintree/saved/index</path>
64
+ <label>Saved Payment Information</label>
65
+ </action>
66
+ </reference>
67
+ </customer_account>
68
+
69
+ <braintree_saved_index translate="label">
70
+ <label>Saved Payment Information</label>
71
+ <update handle="customer_account"/>
72
+ <!-- Mage_Customer -->
73
+ <reference name="root">
74
+ <action method="setTemplate"><template>page/2columns-left.phtml</template></action>
75
+ </reference>
76
+ <reference name="my.account.wrapper">
77
+ <block type="gene_braintree/saved" name="gene_braintree_saved_payments" template="gene/braintree/customer/saved.phtml">
78
+ <block type="gene_braintree/saved" name="gene_braintree_saved_payments_method" as="methods" template="gene/braintree/customer/methods.phtml" />
79
+ </block>
80
+ </reference>
81
+ </braintree_saved_index>
82
+
83
+ </layout>
app/design/frontend/base/default/template/gene/braintree/creditcard.phtml ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Gene_Braintree_Block_Creditcard */
3
+ $_code = $this->getMethodCode()
4
+ ?>
5
+ <div id="payment_form_<?php echo $_code ?>" style="display:none;" class="form-list">
6
+
7
+ <?php if($this->hasSavedDetails() && $this->getMethod()->isVaultEnabled()): ?>
8
+
9
+ <label><?php echo $this->__('Saved Cards'); ?></label>
10
+ <p><?php echo $this->__('The following credit cards accounts are currently linked with your account.'); ?></p>
11
+ <table cellspacing="0" cellpadding="0" id="creditcard-saved-accounts">
12
+ <?php
13
+ $count = 0;
14
+ foreach($this->getSavedDetails() as $savedDetail):
15
+ ?>
16
+ <tr>
17
+ <td width="20">
18
+ <?php if($this->getMethod()->is3DEnabled()): ?>
19
+ <input type="radio" name="payment[card_payment_method_token]" id="<?php echo $savedDetail->token; ?>" data-token="<?php echo $savedDetail->token; ?>" data-threedsecure-nonce="<?php echo $this->getMethod()->getThreeDSecureVaultNonce($savedDetail->token); ?>" value="threedsecure"<?php echo ($count == 0 ? ' checked="checked"' : ''); ?>/>
20
+ <?php else: ?>
21
+ <input type="radio" name="payment[card_payment_method_token]" id="<?php echo $savedDetail->token; ?>" value="<?php echo $savedDetail->token; ?>"<?php echo ($count == 0 ? ' checked="checked"' : ''); ?>/>
22
+ <?php endif; ?>
23
+ </td>
24
+ <td valign="middle">
25
+ <label for="<?php echo $savedDetail->token; ?>" style="line-height: 48px;">
26
+ <img src="<?php echo $this->getSkinUrl('images/gene/braintree/' . $this->getCardIcon($savedDetail->cardType)) ?>" align="left" />&nbsp;&nbsp; xxxx - xxxx - xxxx - <?php echo $savedDetail->last4; ?> &nbsp;&nbsp;&nbsp; <em><?php echo $this->__('Expires:'); ?></em> <?php echo $savedDetail->expirationMonth; ?>/<?php echo $savedDetail->expirationYear; ?>
27
+ </label>
28
+ </td>
29
+ </tr>
30
+ <?php
31
+ ++$count;
32
+ endforeach; ?>
33
+ <tr>
34
+ <td width="20"><input type="radio" name="payment[card_payment_method_token]" id="other-creditcard" value="other" /></td>
35
+ <td><label for="other-creditcard"><?php echo $this->__('New Credit Card'); ?></label></td>
36
+ </tr>
37
+ </table>
38
+
39
+ <?php endif; ?>
40
+
41
+ <div id="credit-card-form"<?php echo ($this->hasSavedDetails() && $this->getMethod()->isVaultEnabled() ? ' style="display: none;"' : ''); ?>>
42
+ <ul class="form-list">
43
+ <li>
44
+ <label for="<?php echo $_code ?>_cc_number" class="required"><em>*</em><?php echo $this->__('Credit Card Number') ?></label>
45
+ <div class="input-box card-number">
46
+ <input type="text" data-genebraintree-name="number" name="payment[cc_number]" id="<?php echo $_code ?>_cc_number" title="<?php echo $this->__('Credit Card Number') ?>" class="input-text validate-cc-number validate-cc-type validate-accepted-type" value=""/>
47
+
48
+ <div class="card-type"><img src="<?php echo $this->getSkinUrl('images/gene/braintree/card.png') ?>" id="card-type-image" /></div>
49
+ </div>
50
+ </li>
51
+ <li id="<?php echo $_code ?>_cc_type_exp_div">
52
+ <label for="<?php echo $_code ?>_expiration" class="required"><em>*</em><?php echo $this->__('Expiration Date') ?></label>
53
+ <div class="input-box">
54
+ <div class="v-fix">
55
+ <select id="<?php echo $_code ?>_expiration" name="payment[cc_exp_month]" data-genebraintree-name="expiration_month" class="month validate-cc-exp required-entry">
56
+ <?php $_ccExpMonth = $this->getInfoData('cc_exp_month') ?>
57
+ <?php foreach ($this->getCcMonths() as $k=>$v): ?>
58
+ <option value="<?php echo $k?$k:'' ?>"<?php if($k==$_ccExpMonth): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
59
+ <?php endforeach ?>
60
+ </select>
61
+ </div>
62
+ <div class="v-fix">
63
+ <?php $_ccExpYear = $this->getInfoData('cc_exp_year') ?>
64
+ <select id="<?php echo $_code ?>_expiration_yr" name="payment[cc_exp_year]" data-genebraintree-name="expiration_year" class="year required-entry">
65
+ <?php foreach ($this->getCcYears() as $k=>$v): ?>
66
+ <option value="<?php echo $k?$k:'' ?>"<?php if($k==$_ccExpYear): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
67
+ <?php endforeach ?>
68
+ </select>
69
+ </div>
70
+ </div>
71
+ </li>
72
+ <?php echo $this->getChildHtml() ?>
73
+ <?php if($this->hasVerification()): ?>
74
+ <li id="<?php echo $_code ?>_cc_type_cvv_div">
75
+ <label for="<?php echo $_code ?>_cc_cid" class="required"><em>*</em><?php echo $this->__('Card Verification Number') ?></label>
76
+ <div class="input-box">
77
+ <div class="v-fix">
78
+ <input type="text" title="<?php echo $this->__('Card Verification Number') ?>" class="input-text cvv required-entry validate-cc-cvn" id="<?php echo $_code ?>_cc_cid" name="payment[cc_cid]" data-genebraintree-name="cvv" value="" />
79
+ </div>
80
+ <a href="#" class="cvv-what-is-this"><?php echo $this->__('What is this?') ?></a>
81
+ </div>
82
+ </li>
83
+ <?php endif; ?>
84
+
85
+ <?php if ($this->canSaveCard()): ?>
86
+ <li id="<?php echo $_code ?>_store_in_vault_div">
87
+ <input type="checkbox" title="<?php echo $this->__('Save this card for future use') ?>"
88
+ class="input-checkbox" id="<?php echo $_code ?>_store_in_vault" name="payment[save_card]"
89
+ value="1"/>
90
+ <label for="<?php echo $_code ?>_store_in_vault" style="float:none;"><?php echo $this->__(
91
+ 'Save this card for future use'
92
+ ) ?></label>
93
+ </li>
94
+ <?php endif; ?>
95
+
96
+ </ul>
97
+
98
+ <!-- Fields for the payment method -->
99
+ <input type="hidden" name="payment[payment_method_nonce]" id="creditcard-payment-nonce" />
100
+
101
+ <input type="hidden" id="<?php echo $_code ?>_cc_type" value="" />
102
+ </div>
103
+
104
+ </div>
105
+
106
+ <style type="text/css">
107
+ .card-number {
108
+ position: relative;
109
+ }
110
+
111
+ .card-type {
112
+ position: absolute;
113
+ top: 0;
114
+ left: 6px;
115
+ }
116
+
117
+ .card-number input {
118
+ height: 46px!important;
119
+ text-indent: 56px!important;
120
+ }
121
+ </style>
122
+
123
+ <script type="text/javascript">
124
+ //<![CDATA[
125
+ Validation.creditCartTypes = $H({
126
+ 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true],
127
+ 'MC': [new RegExp('^5[1-5][0-9]{14}$'), new RegExp('^[0-9]{3}$'), true],
128
+ 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true],
129
+ 'DI': [new RegExp('^6011[0-9]{12}$'), new RegExp('^[0-9]{3}$'), true],
130
+ 'JCB': [new RegExp('^(3[0-9]{15}|(2131|1800)[0-9]{11})$'), new RegExp('^[0-9]{4}$'), true],
131
+ 'OT': [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), false],
132
+ 'ME': [new RegExp('^(?:5[0678][0-9]{2}|6304|6390|67[0-9]{2})[0-9]{8,15}$'), new RegExp('^[0-9]{3}$'), true]
133
+ });
134
+ //]]>
135
+ </script>
136
+
137
+ <!-- Attach an event onto all radio buttons -->
138
+ <script type="text/javascript">
139
+
140
+ // Set a flag to determine whether the PayPal flag is initialized
141
+ var CreditCardInit = false;
142
+
143
+ // Wrap our logic in a function so we can init in different ways
144
+ initCreditCard = function() {
145
+
146
+ // Verify that vzero is defined before attempting to use it
147
+ if (typeof vzero !== 'undefined') {
148
+
149
+ // Tell the system we're init
150
+ CreditCardInit = true;
151
+
152
+ // Always set the amount as it's needed within 3D secure requests
153
+ vzero.setAmount('<?php echo Mage::getSingleton('checkout/cart')->getQuote()->collectTotals()->getGrandTotal(); ?>');
154
+
155
+ // We now need to set this information into the browser
156
+ vzero.setBillingName("<?php echo $this->jsQuoteEscape(Mage::getSingleton('checkout/session')->getQuote()->getBillingAddress()->getName(), '"'); ?>");
157
+ vzero.setBillingPostcode("<?php echo $this->jsQuoteEscape(Mage::getSingleton('checkout/session')->getQuote()->getBillingAddress()->getPostcode(), '"'); ?>");
158
+
159
+ // Set the accepted cards
160
+ vzero.setAcceptedCards(<?php echo $this->getCcAvailableTypes(); ?>);
161
+ }
162
+
163
+ // Loop through each saved card being selected
164
+ $$('#creditcard-saved-accounts input[type="radio"]').each(function (elm) {
165
+
166
+ // Observe the elements changing
167
+ Element.observe(elm, 'change', function (event) {
168
+
169
+ // Has the user selected other?
170
+ if ($$('#creditcard-saved-accounts input:checked[type=radio]').first().value == 'other') {
171
+
172
+ // Show the credit card form
173
+ $('credit-card-form').show();
174
+
175
+ // Enable the credit card form all the elements in the credit card form
176
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
177
+ formElement.removeAttribute('disabled');
178
+ });
179
+
180
+ } else {
181
+
182
+ // Hide the new credit card form
183
+ $('credit-card-form').hide();
184
+
185
+ // Disable all the elements in the credit card form
186
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
187
+ formElement.setAttribute('disabled', 'disabled');
188
+ });
189
+
190
+ }
191
+ });
192
+ });
193
+
194
+ // Observe the card type
195
+ if(typeof vzero !== "undefined") {
196
+ vzero.observeCardType();
197
+ }
198
+
199
+ };
200
+
201
+ // Load up credit card
202
+ initCreditCard();
203
+
204
+ // If the function didn't run on the load of the payment method do it on dom:loaded
205
+ if(!CreditCardInit) {
206
+ document.observe('dom:loaded', function () {
207
+ initCreditCard();
208
+ });
209
+ }
210
+
211
+ // Add our new validation type
212
+ Validation.add('validate-accepted-type', 'Sadly, we\'re unable to accept this type of card, please try another.', function(v) {
213
+ if($('<?php echo $_code ?>_cc_type') != undefined) {
214
+ if (vzero.getAcceptedCards().indexOf($('<?php echo $_code ?>_cc_type').value) == -1) {
215
+ return false;
216
+ }
217
+ }
218
+ return true;
219
+ });
220
+
221
+ // Update a couple of the messages
222
+ if(Validation.get('validate-cc-type') != undefined) {
223
+ Validation.get('validate-cc-type').error = "<?php echo $this->__('We cannot detect the card type for this card number, please try re-entering your card details.'); ?>";
224
+ }
225
+ if(Validation.get('validate-cc-number') != undefined) {
226
+ Validation.get('validate-cc-number').error = "<?php echo $this->__('We cannot match this card number to any of our accepted payment methods, please try re-entering your details.'); ?>"
227
+ }
228
+ </script>
app/design/frontend/base/default/template/gene/braintree/creditcard/info.phtml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p><strong><?php echo $this->escapeHtml($this->getMethod()->getTitle()) ?></strong></p>
2
+
3
+ <?php if ($_specificInfo = $this->getSpecificInformation()):?>
4
+ <table>
5
+ <tbody>
6
+ <?php foreach ($_specificInfo as $_label => $_value):
7
+ if($_value): ?>
8
+ <tr>
9
+ <th style="text-align: left;font-weight:bold;padding: 3px 0;"><?php echo $this->escapeHtml($_label)?>:</th>
10
+ </tr>
11
+ <tr>
12
+ <td style="padding: 3px 0;"><?php echo nl2br(implode($this->getValueAsArray($_value, true), "\n"))?></td>
13
+ </tr>
14
+ <?php endif;
15
+ endforeach; ?>
16
+ </tbody>
17
+ </table>
18
+ <?php endif;?>
19
+
20
+ <?php echo $this->getChildHtml()?>
app/design/frontend/base/default/template/gene/braintree/creditcard/threedsecure.phtml ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <!-- 3D Secure Container -->
2
+ <div id="3dsecure_container"></div>
app/design/frontend/base/default/template/gene/braintree/customer/methods.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if($savedDetails = $this->getSavedDetails($this->getType())): ?>
2
+
3
+ <table width="100%">
4
+ <?php foreach($savedDetails as $savedDetail): ?>
5
+ <tr>
6
+ <td width="60">
7
+ <img src="<?php echo $this->getSkinUrl('images/gene/braintree/' . Gene_Braintree_Block_Creditcard::getCardIcon((isset($savedDetail->cardType) ? $savedDetail->cardType : 'paypal'))); ?>" />
8
+ </td>
9
+ <td>
10
+ <?php if(isset($savedDetail->cardType)): ?>
11
+ xxxx - xxxx - xxxx - <?php echo $savedDetail->last4; ?> &nbsp;&nbsp;&nbsp; <em><?php echo $this->__('Expires:'); ?></em> <?php echo $savedDetail->expirationMonth; ?>/<?php echo $savedDetail->expirationYear; ?>
12
+ <?php else: ?>
13
+ <?php echo $savedDetail->email; ?>
14
+ <?php endif; ?>
15
+ </td>
16
+ <td>
17
+ <a href="<?php echo $this->getUrl('*/*/remove', array('id' => $savedDetail->token)); ?>" onclick="if(!confirm('<?php echo $this->__('Are you sure you want to remove this payment method?'); ?>')) { return false }"><?php echo $this->__('Remove'); ?></a>
18
+ </td>
19
+ </tr>
20
+ <?php endforeach; ?>
21
+ </table>
22
+
23
+ <?php endif; ?>
app/design/frontend/base/default/template/gene/braintree/customer/saved.phtml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="page-title">
2
+ <h1><?php echo $this->__('Saved Payment Information') ?></h1>
3
+ </div>
4
+
5
+ <?php echo $this->getMessagesBlock()->toHtml() ?>
6
+
7
+ <div class="fieldset">
8
+
9
+ <?php if($this->hasSavedDetails()): ?>
10
+
11
+ <p><?php echo $this->__('You\'re able to use any of the listed payment methods below when purchasing through our checkout, you\'re able to add new payment methods within the checkout.'); ?></p>
12
+
13
+ <div class="col2-set">
14
+
15
+ <?php if($this->hasSavedDetails(Gene_Braintree_Model_Saved::SAVED_CREDITCARD_ID)): ?>
16
+ <div class="col-1">
17
+ <h2 class="legend"><?php echo $this->__('Cards') ?></h2>
18
+ <?php echo $this->getChild('methods')->setType(Gene_Braintree_Model_Saved::SAVED_CREDITCARD_ID)->toHtml(); ?>
19
+ </div>
20
+ <?php endif; ?>
21
+
22
+ <?php if($this->hasSavedDetails(Gene_Braintree_Model_Saved::SAVED_PAYPAL_ID)): ?>
23
+ <div class="col-1">
24
+ <h2 class="legend"><?php echo $this->__('PayPal') ?></h2>
25
+ <?php echo $this->getChild('methods')->setType(Gene_Braintree_Model_Saved::SAVED_PAYPAL_ID)->toHtml(); ?>
26
+ </div>
27
+ <?php endif; ?>
28
+
29
+ </div>
30
+
31
+ <?php else: ?>
32
+ <p><?php echo $this->__('You currently have no saved payment information, you can save a payment method when making a purchase.'); ?></p>
33
+ <?php endif; ?>
34
+ </div>
app/design/frontend/base/default/template/gene/braintree/js/amasty.phtml ADDED
@@ -0,0 +1,375 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Add in support for Amasty One Step Checkout
4
+ * https://amasty.com/single-step-checkout.html
5
+ */
6
+ ?>
7
+ <script type="text/javascript">
8
+
9
+ // Older versions of the checkout don't contain this variable
10
+ if(typeof checkoutRunning == 'undefined') {
11
+ var checkoutRunning = false;
12
+ }
13
+
14
+ // Check that we haven't already set the original complete checkout method
15
+ if(originalCompleteCheckout === undefined && completeCheckout !== undefined) {
16
+
17
+ // Store the old complete checkout function
18
+ var originalCompleteCheckout = completeCheckout;
19
+
20
+ // Re-define the original method so we can do some jazz with it
21
+ completeCheckout = function () {
22
+
23
+ // Device data should never be disabled
24
+ $('device_data').removeAttribute('disabled');
25
+
26
+ // Always attempt to update the card type on submission
27
+ if($$('[data-genebraintree-name="number"]').first() != undefined) {
28
+ vzero.updateCardType($$('[data-genebraintree-name="number"]').first().value);
29
+ }
30
+
31
+ // Run the original validation functions
32
+ if (amscheckoutForm.validator.validate() && !checkoutRunning) {
33
+
34
+ // Are we dealing with the credit card method?
35
+ if (payment.currentMethod == 'gene_braintree_creditcard') {
36
+
37
+ // Update the data as we're in a one step
38
+ vzero.updateData(function() {
39
+
40
+ // Grab these directly from the form and update
41
+ if ($('billing:firstname') != undefined && $('billing:lastname') != undefined) {
42
+ vzero.setBillingName($('billing:firstname').value + ' ' + $('billing:lastname').value);
43
+ }
44
+ if ($('billing:postcode') != undefined) {
45
+ vzero.setBillingPostcode($('billing:postcode').value);
46
+ }
47
+
48
+ // Check is running
49
+ checkoutRunning = true;
50
+
51
+ // Show the loading
52
+ showLoading();
53
+
54
+ // Process the card
55
+ vzero.process({
56
+ onSuccess: function () {
57
+
58
+ // Disable the standard credit card form so the values don't get passed through to the checkout
59
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
60
+ if (formElement.id != 'creditcard-payment-nonce' && formElement.getAttribute('data-genebraintree-name') != 'cvv' && formElement.id != 'gene_braintree_creditcard_store_in_vault' && formElement.id != 'device_data') {
61
+ formElement.setAttribute('disabled', 'disabled');
62
+ }
63
+ });
64
+
65
+ // No longer running
66
+ checkoutRunning = false;
67
+
68
+ // Fire the original event and return the response
69
+ completeCheckoutResponse = originalCompleteCheckout.apply(this, arguments);
70
+
71
+ // Re-enable any form elements which were disabled
72
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
73
+ formElement.removeAttribute('disabled');
74
+ });
75
+
76
+ // Run the original function
77
+ return completeCheckoutResponse;
78
+ },
79
+ onFailure: function() {
80
+
81
+ // Reset the waiting for the parent function
82
+ hideLoading();
83
+
84
+ // No longer running
85
+ checkoutRunning = false;
86
+
87
+ }
88
+ });
89
+
90
+ });
91
+
92
+ // We're updating data don't do anything else for now
93
+ return false;
94
+
95
+ }
96
+
97
+ }
98
+
99
+ // Stop further processing
100
+ return originalCompleteCheckout.apply(this, arguments);
101
+ };
102
+ }
103
+
104
+ // Only intercept the payment method once
105
+ if(paymentOriginal == undefined) {
106
+
107
+ // It's not been ran so set it to false
108
+ var PayPalCompleteRan = false;
109
+
110
+ /**
111
+ * Function to run once PayPal has been completed
112
+ */
113
+ completePayPal = function(obj) {
114
+
115
+ // Check the flag to make sure we're good to run the function
116
+ if(!PayPalCompleteRan) {
117
+
118
+ // Mark the flag as true
119
+ PayPalCompleteRan = true;
120
+
121
+ // Force check
122
+ payment.switchMethod('gene_braintree_paypal', true);
123
+
124
+ // Re-enable the form
125
+ $('paypal-payment-nonce').removeAttribute('disabled');
126
+ $('paypal-payment-nonce').value = obj.nonce;
127
+
128
+ // Show the button again
129
+ hidePayPalButton();
130
+
131
+ // No longer running
132
+ checkoutRunning = false;
133
+
134
+ // Show the loading thing
135
+ showLoading();
136
+
137
+ // Run the complete checkout method
138
+ return completeCheckout();
139
+
140
+ }
141
+
142
+ };
143
+
144
+ // Flag to check if the PayPal button is already loading
145
+ var PayPalButtonLoading = false;
146
+
147
+ /**
148
+ * Easily add the PayPal button into the DOM
149
+ */
150
+ addPayPalButton = function() {
151
+
152
+ // Check we can locate the submit button
153
+ if($$('.amscheckout-submit').first() != undefined && $('paypal-complete') == undefined && PayPalButtonLoading == false) {
154
+
155
+ // The button is loading
156
+ PayPalButtonLoading = true;
157
+
158
+ // As the PayPal button has to request data from the server show the loader
159
+ showLoading();
160
+
161
+ // Update the data contained within the classes
162
+ vzero.updateData(function () {
163
+
164
+ // The button is no longer loading
165
+ PayPalButtonLoading = false;
166
+
167
+ // Hide it once we're done
168
+ hideLoading();
169
+
170
+ // Validate the payment method is still correct
171
+ if(payment.currentMethod == 'gene_braintree_paypal' && $('paypal-complete') == undefined) {
172
+
173
+ // Set the flag to false as we've created a new button
174
+ PayPalCompleteRan = false;
175
+
176
+ // Hide the submit button
177
+ $$('.amscheckout-submit').first().hide();
178
+
179
+ // Add in our PayPal button
180
+ $$('.amscheckout-submit').first().up().insert('<div id="paypal-complete"><label id="paypal-label"><?php echo $this->__('Complete checkout with'); ?> </label><div id="paypal-container"></div></div>');
181
+
182
+ // Always stop the window from opening
183
+ $('paypal-complete').observe('click', function(event) {
184
+
185
+ // Validate the form before we open the PayPal modal window
186
+ if (!amscheckoutForm.validator.validate() || checkoutRunning) {
187
+
188
+ // Sadly we're unable to intercept the PayPal window in any other way then just hard closing it
189
+ vzeroPaypal.closePayPalWindow();
190
+ }
191
+ });
192
+
193
+ // Add in the PayPal button
194
+ vzeroPaypal.addPayPalButton({
195
+ onSuccess: completePayPal
196
+ });
197
+
198
+ }
199
+
200
+ });
201
+
202
+ } else if($('paypal-complete') != undefined) {
203
+
204
+ // The button is loading
205
+ PayPalButtonLoading = true;
206
+
207
+ // As the PayPal button has to request data from the server show the loader
208
+ showLoading();
209
+
210
+ // Update the data contained within the classes
211
+ vzero.updateData(function () {
212
+
213
+ // The button is no longer loading
214
+ PayPalButtonLoading = false;
215
+
216
+ // Hide it once we're done
217
+ hideLoading();
218
+
219
+ // Validate the payment method is still correct
220
+ if(payment.currentMethod == 'gene_braintree_paypal') {
221
+
222
+ // Set the flag to false as we've created a new button
223
+ PayPalCompleteRan = false;
224
+
225
+ // Hide the submit button
226
+ $$('.amscheckout-submit').first().hide();
227
+
228
+ // Add in the PayPal button
229
+ $('paypal-complete').show();
230
+
231
+ }
232
+
233
+ });
234
+
235
+ }
236
+
237
+ };
238
+
239
+ /**
240
+ * As we need to remove the PayPal button in multiple places
241
+ */
242
+ hidePayPalButton = function() {
243
+
244
+ // If the user has selected a different payment method make some modifications
245
+ if($$('.amscheckout-submit').first() != undefined) {
246
+ $$('.amscheckout-submit').first().show();
247
+ }
248
+
249
+ // Remove the PayPal element
250
+ if($('paypal-complete') != undefined) {
251
+ $('paypal-complete').hide();
252
+ }
253
+
254
+ };
255
+
256
+ // Check if the payment method is the default
257
+ if(payment !== undefined) {
258
+ if((payment.currentMethod == 'gene_braintree_paypal' && $('paypal-saved-accounts') == undefined) || ($$('#paypal-saved-accounts input:checked[type=radio]').first() != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other')) {
259
+
260
+ // Verify that vzero is defined before attempting to use it
261
+ if(typeof vzeroPaypal !== 'undefined') {
262
+
263
+ // Always set the amount as it's needed within 3D secure requests
264
+ vzeroPaypal.setPricing('<?php echo Mage::getSingleton('checkout/cart')->getQuote()->collectTotals()->getGrandTotal(); ?>', '<?php echo Mage::getSingleton('checkout/cart')->getQuote()->getBaseCurrencyCode(); ?>');
265
+ }
266
+
267
+ addPayPalButton();
268
+ }
269
+ }
270
+
271
+ // Store the original payment method
272
+ var paymentOriginal = Payment.prototype.switchMethod;
273
+
274
+ // Intercept the save function
275
+ Payment.prototype.switchMethod = function (method) {
276
+
277
+ // Make sure the paypal complete action hasn't just ran
278
+ if(PayPalCompleteRan != true) {
279
+
280
+ // Detect PayPal choice
281
+ if (method == 'gene_braintree_paypal') {
282
+
283
+ if ($('paypal-saved-accounts') == undefined) {
284
+ addPayPalButton();
285
+ } else if ($('paypal-saved-accounts') != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first() != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other') {
286
+ addPayPalButton();
287
+ } else {
288
+ hidePayPalButton();
289
+ }
290
+
291
+ } else {
292
+ hidePayPalButton();
293
+ }
294
+ }
295
+
296
+
297
+ // Run the original function
298
+ return paymentOriginal.apply(this, arguments);
299
+
300
+ };
301
+
302
+ // If we have any saved accounts we'll need to do something jammy
303
+ if($$('#paypal-saved-accounts input[type=radio]').first() != undefined) {
304
+
305
+ // Loop through each radio button
306
+ $$('#paypal-saved-accounts input[type=radio]').each(function (savedAccount) {
307
+
308
+ // Observe them changing
309
+ Event.observe(savedAccount, 'click', function (ele) {
310
+ if(savedAccount.value == 'other') {
311
+ addPayPalButton();
312
+ } else {
313
+ hidePayPalButton();
314
+ }
315
+ });
316
+ });
317
+ }
318
+
319
+ var updateCheckoutOriginal = updateCheckout;
320
+ updateCheckout = function() {
321
+
322
+ // If we're updating the checkout remove the PayPal button
323
+ hidePayPalButton();
324
+
325
+ // Run the original function
326
+ return updateCheckoutOriginal.apply(this, arguments);
327
+ };
328
+
329
+ // What should happen if the user closes the 3D secure window?
330
+ vzero.close3dSecureMethod(function() {
331
+
332
+ // Hide the loading
333
+ hideLoading();
334
+
335
+ // Check is running
336
+ checkoutRunning = false;
337
+
338
+ });
339
+
340
+ // Observe the card type here as it'll fail within creditCard.phtml
341
+ vzero.observeCardType();
342
+
343
+ // Observe all Ajax requests for changes
344
+ vzero.observeAjaxRequests(function() {
345
+
346
+ // If the method is PayPal remove and re-add the PayPal button
347
+ if(payment.currentMethod == 'gene_braintree_paypal') {
348
+ hidePayPalButton();
349
+ addPayPalButton();
350
+ } else {
351
+ vzero.updateData();
352
+ }
353
+
354
+ });
355
+
356
+ }
357
+ </script>
358
+ <style type="text/css">
359
+ #paypal-label {
360
+ line-height: 44px;
361
+ float: left;
362
+ margin-right: 12px;
363
+ }
364
+ #braintree-paypal-button {
365
+ line-height: unset;
366
+ padding: 0;
367
+ float: left;
368
+ }
369
+ #braintree-paypal-loggedin {
370
+ display: none!important;
371
+ }
372
+ #braintree-paypal-loggedout {
373
+ display: block!important;
374
+ }
375
+ </style>
app/design/frontend/base/default/template/gene/braintree/js/data.phtml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Include the crucial braintree-data.js for fraud protection
4
+ */
5
+ ?>
6
+ <script src="https://js.braintreegateway.com/v1/braintree-data.js"></script>
7
+ <script>
8
+ <?php if($kountId = Mage::getStoreConfig('payment/gene_braintree_creditcard/kount_merchant_id')): ?>
9
+ var env = BraintreeData.environments.production.withId("<?php echo $kountId; ?>");
10
+ <?php else: ?>
11
+ var env = BraintreeData.environments.<?php echo Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_ENVIRONMENT_PATH); ?>;
12
+ <?php endif; ?>
13
+ BraintreeData.setup("<?php echo Mage::getStoreConfig(Gene_Braintree_Model_Wrapper_Braintree::BRAINTREE_MERCHANT_ID_PATH); ?>", '<?php echo ($this->getPaymentFormId() ? $this->getPaymentFormId() : 'co-payment-form'); ?>', env);
14
+ </script>
15
+
app/design/frontend/base/default/template/gene/braintree/js/default.phtml ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Intercept various functions for the default checkout flow
4
+ */
5
+ ?>
6
+ <script type="text/javascript">
7
+
8
+ // Store the current paymentMethod
9
+ var paymentMethod = false;
10
+
11
+ // Store the original payment method
12
+ var paymentOriginal = Payment.prototype.save;
13
+
14
+ // Intercept the save function
15
+ Payment.prototype.save = function() {
16
+
17
+ if (checkout.loadWaiting != false) return;
18
+
19
+ // Update our paymentMethod
20
+ paymentMethod = this.currentMethod;
21
+
22
+ // Check we're dealing with the current method
23
+ if (paymentMethod == 'gene_braintree_creditcard') {
24
+
25
+ // Always attempt to update the card type on submission
26
+ if($$('[data-genebraintree-name="number"]').first() != undefined) {
27
+ vzero.updateCardType($$('[data-genebraintree-name="number"]').first().value);
28
+ }
29
+
30
+ // Set the payment to loading
31
+ checkout.setLoadWaiting('payment');
32
+
33
+ // Do the standard validation
34
+ var validator = new Validation(this.form);
35
+ if (this.validate() && validator.validate()) {
36
+
37
+ // Store these to be used later on
38
+ var paymentThis = this;
39
+ var paymentArgs = arguments;
40
+
41
+ // Process the card
42
+ vzero.process({
43
+ onSuccess: function () {
44
+
45
+ // Reset the waiting for the parent function
46
+ checkout.setLoadWaiting(false);
47
+
48
+ // Disable the standard credit card form so the values don't get passed through to the checkout
49
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
50
+ if (formElement.id != 'creditcard-payment-nonce' && formElement.getAttribute('data-genebraintree-name') != 'cvv' && formElement.id != 'gene_braintree_creditcard_store_in_vault' && formElement.id != 'device_data') {
51
+ formElement.setAttribute('disabled', 'disabled');
52
+ }
53
+ });
54
+
55
+ // Fire the original event and return the response
56
+ paymentResponse = paymentOriginal.apply(paymentThis, paymentArgs);
57
+
58
+ // Re-enable any form elements which were disabled
59
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
60
+ formElement.removeAttribute('disabled');
61
+ });
62
+
63
+ // Run the original function
64
+ return paymentResponse;
65
+ },
66
+ onFailure: function() {
67
+ checkout.setLoadWaiting(false);
68
+ }
69
+ });
70
+ } else {
71
+ checkout.setLoadWaiting(false);
72
+ }
73
+
74
+ } else {
75
+ // Proxy the function through
76
+ return paymentOriginal.apply(this, arguments);
77
+ }
78
+ };
79
+
80
+ // Store the original payment method
81
+ var reviewInitOriginal = Review.prototype.initialize;
82
+
83
+ // Intercept the save function
84
+ Review.prototype.initialize = function(saveUrl, successUrl, agreementsForm) {
85
+
86
+ // Do the original action
87
+ var reviewResponse = reviewInitOriginal.apply(this, arguments);
88
+
89
+ // Swap out the buttons
90
+ if((paymentMethod == 'gene_braintree_paypal' && $('paypal-saved-accounts') == undefined) || ($$('#paypal-saved-accounts input:checked[type=radio]').first() != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other')) {
91
+
92
+ // Hide the checkout button
93
+ if ($$('#review-buttons-container button').first() != undefined) {
94
+ $$('#review-buttons-container button').first().hide();
95
+ }
96
+
97
+ // Insert out PayPal button
98
+ $('review-buttons-container').insert('<div id="paypal-complete"><label id="paypal-label"><?php echo $this->__('Complete checkout with'); ?> </label><div id="paypal-container"></div></div>');
99
+
100
+ // Add in the PayPal button
101
+ vzeroPaypal.addPayPalButton();
102
+
103
+ // Style the label nicely
104
+ $('paypal-label').setStyle({
105
+ 'lineHeight': '44px',
106
+ 'float': 'left',
107
+ 'marginRight': '12px'
108
+ });
109
+
110
+ // If this button exists swap some minor styling things
111
+ if($('braintree-paypal-button') != undefined) {
112
+
113
+ // Fix some styling issues where we're placing the button
114
+ $('braintree-paypal-button').setStyle({
115
+ 'lineHeight': 'auto',
116
+ 'padding': '0',
117
+ 'float': 'left'
118
+ });
119
+ }
120
+
121
+ } else {
122
+
123
+ // Revert our madness
124
+ if ($$('#review-buttons-container button').first() != undefined) {
125
+ $$('#review-buttons-container button').first().show();
126
+ }
127
+
128
+ // Remove the PayPal element
129
+ if($$('#paypal-complete').first() != undefined) {
130
+ $('paypal-complete').remove();
131
+ }
132
+ }
133
+
134
+ // If we're using braintree credit card disable the form on submission
135
+ if (paymentMethod == 'gene_braintree_creditcard') {
136
+
137
+ // Re-enable the form elements just in case something went wrong
138
+ $$('#credit-card-form input, #credit-card-form select').each(function(formElement) {
139
+ formElement.removeAttribute('disabled');
140
+ });
141
+ }
142
+
143
+ // Return the normal response
144
+ return reviewResponse;
145
+
146
+ };
147
+
148
+ // Store the original payment method
149
+ var reviewSaveOriginal = Review.prototype.save;
150
+
151
+ // Intercept the save function
152
+ Review.prototype.save = function() {
153
+
154
+ // If we're using braintree credit card disable the form on submission
155
+ if (paymentMethod == 'gene_braintree_creditcard') {
156
+
157
+ // Disable the standard credit card form so the values don't get passed through to the checkout
158
+ $$('#credit-card-form input, #credit-card-form select').each(function(formElement) {
159
+ if(formElement.id != 'creditcard-payment-nonce' && formElement.getAttribute('data-genebraintree-name') != 'cvv' && formElement.id != 'gene_braintree_creditcard_store_in_vault' && formElement.id != 'device_data') {
160
+ formElement.setAttribute('disabled', 'disabled');
161
+ }
162
+ });
163
+ }
164
+
165
+ // Do the original action
166
+ var reviewSaveResponse = reviewSaveOriginal.apply(this, arguments);
167
+
168
+ // If we're using braintree credit card disable the form on submission
169
+ if (paymentMethod == 'gene_braintree_creditcard') {
170
+
171
+ // Re-enable the form elements just in case something went wrong
172
+ $$('#credit-card-form input, #credit-card-form select').each(function(formElement) {
173
+ formElement.removeAttribute('disabled');
174
+ });
175
+ }
176
+
177
+ return reviewSaveResponse;
178
+ };
179
+
180
+ vzero.close3dSecureMethod(function() {
181
+
182
+ // Re-tokenize all the saved cards
183
+ vzero.tokenize3dSavedCards(function() {
184
+ checkout.setLoadWaiting(false);
185
+ });
186
+
187
+ });
188
+ </script>
app/design/frontend/base/default/template/gene/braintree/js/idev.phtml ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Add in support for onestepcheckout.com
4
+ * http://onestepcheckout.com
5
+ */
6
+ ?>
7
+ <script type="text/javascript">
8
+
9
+ // Flag to skip over our interception if needed
10
+ var processedVZero = false;
11
+
12
+ // Hook onto the event that submits the entire form
13
+ // Apparently there may be more than one of these buttons
14
+ $$('.onestepcheckout-place-order').each(function(elem){
15
+
16
+ // Observe the click event
17
+ elem.observe('click', function(e) {
18
+
19
+ // Device data should never be disabled
20
+ if($('device_data') != undefined) {
21
+ $('device_data').removeAttribute('disabled');
22
+ }
23
+
24
+ // Check to see if we've already processed the form?
25
+ if(!processedVZero) {
26
+
27
+ // Always attempt to update the card type on submission
28
+ if($$('[data-genebraintree-name="number"]').first() != undefined) {
29
+ vzero.updateCardType($$('[data-genebraintree-name="number"]').first().value);
30
+ }
31
+
32
+ // First validate the form
33
+ var form = new VarienForm('onestepcheckout-form');
34
+
35
+ // Validate the form like the parent method
36
+ if(!form.validator.validate()) {
37
+
38
+ // We want to stop any further events
39
+ Event.stop(e);
40
+
41
+ } else {
42
+
43
+ // Are we dealing with the credit card method?
44
+ if (payment.currentMethod == 'gene_braintree_creditcard') {
45
+
46
+ // Set this flag to stop the other function from firing
47
+ already_placing_order = true;
48
+
49
+ startLoading();
50
+
51
+ // Update the data as we're in a one step
52
+ vzero.updateData(function() {
53
+
54
+ // Grab these directly from the form and update
55
+ if ($('billing:firstname') != undefined && $('billing:lastname') != undefined) {
56
+ vzero.setBillingName($('billing:firstname').value + ' ' + $('billing:lastname').value);
57
+ }
58
+ if ($('billing:postcode') != undefined) {
59
+ vzero.setBillingPostcode($('billing:postcode').value);
60
+ }
61
+
62
+ // Process the card
63
+ vzero.process({
64
+ onSuccess: function () {
65
+
66
+ // Disable the standard credit card form so the values don't get passed through to the checkout
67
+ $$('#credit-card-form input, #credit-card-form select').each(function (formElement) {
68
+ if (formElement.id != 'creditcard-payment-nonce' && formElement.getAttribute('data-genebraintree-name') != 'cvv' && formElement.id != 'gene_braintree_creditcard_store_in_vault' && formElement.id != 'device_data') {
69
+ formElement.setAttribute('disabled', 'disabled');
70
+ }
71
+ });
72
+
73
+ stopLoading();
74
+
75
+ // Set the flag to true
76
+ processedVZero = true;
77
+
78
+ // We're no longer stopping the events
79
+ already_placing_order = false;
80
+
81
+ // Fire the same event over again
82
+ $(elem).click();
83
+ },
84
+ onFailure: function() {
85
+
86
+ // Set the flag to true
87
+ processedVZero = false;
88
+
89
+ stopLoading();
90
+
91
+ // We're no longer stopping the events
92
+ already_placing_order = false;
93
+
94
+ }
95
+ });
96
+ });
97
+
98
+ }
99
+ }
100
+
101
+ }
102
+
103
+ });
104
+ });
105
+
106
+ // It's not been ran so set it to false
107
+ var PayPalCompleteRan = false;
108
+
109
+ /**
110
+ * Wrap the functionality needed to start loading
111
+ **/
112
+ startLoading = function(noMessage) {
113
+
114
+ var submitElement = $('onestepcheckout-place-order');
115
+
116
+ /* Disable button to avoid multiple clicks */
117
+ submitElement.removeClassName('orange').addClassName('grey');
118
+ submitElement.disabled = true;
119
+
120
+ // Add in our loader event
121
+ var loaderElement = new Element('span').
122
+ addClassName('onestepcheckout-place-order-loading');
123
+
124
+ if(noMessage != true) {
125
+ loaderElement.update('<?php echo $this->__('Please wait, processing your order...'); ?>');
126
+ }
127
+
128
+ // Append it into the correct area
129
+ submitElement.parentNode.appendChild(loaderElement);
130
+
131
+ };
132
+
133
+ /**
134
+ * Wrap the functionality to stop things loading
135
+ **/
136
+ stopLoading = function() {
137
+
138
+ // Grab the submit button
139
+ submitElement = $('onestepcheckout-place-order');
140
+
141
+ // Remove the loading stuff on the form
142
+ submitElement.addClassName('orange').removeClassName('grey');
143
+ submitElement.removeAttribute('disabled');
144
+
145
+ // Remove the loader element
146
+ if(submitElement.next('.onestepcheckout-place-order-loading') != undefined) {
147
+ submitElement.next('.onestepcheckout-place-order-loading').remove();
148
+ }
149
+
150
+ };
151
+
152
+ /**
153
+ * Function to run once PayPal has been completed
154
+ */
155
+ completePayPal = function(obj) {
156
+
157
+ // Check the flag to make sure we're good to run the function
158
+ if(!PayPalCompleteRan) {
159
+
160
+ // Mark the flag as true
161
+ PayPalCompleteRan = true;
162
+
163
+ // Force check
164
+ payment.switchMethod('gene_braintree_paypal');
165
+
166
+ // Re-enable the form
167
+ $('paypal-payment-nonce').removeAttribute('disabled');
168
+ $('paypal-payment-nonce').value = obj.nonce;
169
+
170
+ // We have to disable the credit card one
171
+ $('creditcard-payment-nonce').setAttribute('disabled', 'disabled');
172
+
173
+ // Hide the button
174
+ hidePayPalButton();
175
+
176
+ // Submit the checkout
177
+ $$('.onestepcheckout-place-order').first().click();
178
+
179
+ }
180
+
181
+ };
182
+
183
+ // Flag to check if the PayPal button is already loading
184
+ var PayPalButtonLoading = false;
185
+
186
+ /**
187
+ * Easily add the PayPal button into the DOM
188
+ */
189
+ addPayPalButton = function() {
190
+
191
+ // Check we can locate the submit button
192
+ if($('onestepcheckout-place-order') != undefined && $('paypal-complete') == undefined && PayPalButtonLoading == false) {
193
+
194
+ // The button is loading
195
+ PayPalButtonLoading = true;
196
+
197
+ // Start the loading process
198
+ startLoading(true);
199
+
200
+ // Update the data contained within the classes
201
+ vzero.updateData(function () {
202
+
203
+ // Cancel said loading process
204
+ stopLoading();
205
+
206
+ // The button is no longer loading
207
+ PayPalButtonLoading = false;
208
+
209
+ // Validate the payment method is still correct
210
+ if(payment.currentMethod == 'gene_braintree_paypal' && $('paypal-complete') == undefined) {
211
+
212
+ // Set the flag to false as we've created a new button
213
+ PayPalCompleteRan = false;
214
+
215
+ // Hide the submit button
216
+ $('onestepcheckout-place-order').hide();
217
+
218
+ // Add in our PayPal button
219
+ $('onestepcheckout-place-order').up().insert('<div id="paypal-complete"><div id="paypal-container"></div><label id="paypal-label"><?php echo $this->__('Complete checkout with'); ?> </label></div>');
220
+
221
+ // Always stop the window from opening
222
+ $('paypal-complete').observe('click', function(event) {
223
+
224
+ // First validate the form
225
+ var form = new VarienForm('onestepcheckout-form');
226
+
227
+ // Validate the form like the parent method
228
+ if(!form.validator.validate()) {
229
+
230
+ // Sadly we're unable to intercept the PayPal window in any other way then just hard closing it
231
+ vzeroPaypal.closePayPalWindow();
232
+ }
233
+ });
234
+
235
+ // Add in the PayPal button
236
+ vzeroPaypal.addPayPalButton({
237
+ onSuccess: completePayPal
238
+ });
239
+ }
240
+
241
+ });
242
+
243
+ } else if($('paypal-complete') != undefined && PayPalButtonLoading == false) {
244
+
245
+ // The button is loading
246
+ PayPalButtonLoading = true;
247
+
248
+ // Start the loading process
249
+ startLoading(true);
250
+
251
+ // Update the data contained within the classes
252
+ vzero.updateData(function () {
253
+
254
+ // The button is no longer loading
255
+ PayPalButtonLoading = false;
256
+
257
+ // Cancel said loading process
258
+ stopLoading();
259
+
260
+ // Validate the payment method is still correct
261
+ if(payment.currentMethod == 'gene_braintree_paypal') {
262
+
263
+ // Set the flag to false as we've created a new button
264
+ PayPalCompleteRan = false;
265
+
266
+ // Hide the submit button
267
+ $('onestepcheckout-place-order').hide();
268
+
269
+ // Add in our PayPal button
270
+ $('paypal-complete').show();
271
+ }
272
+
273
+ });
274
+
275
+ }
276
+
277
+ };
278
+
279
+ /**
280
+ * As we need to remove the PayPal button in multiple places
281
+ */
282
+ hidePayPalButton = function() {
283
+
284
+ // Just in case things are still loading
285
+ stopLoading();
286
+
287
+ // If the user has selected a different payment method make some modifications
288
+ if($('onestepcheckout-place-order') != undefined) {
289
+ $('onestepcheckout-place-order').show();
290
+ }
291
+
292
+ // Remove the PayPal element
293
+ if($('paypal-complete') != undefined) {
294
+ $('paypal-complete').hide();
295
+ }
296
+
297
+ };
298
+
299
+ // Check if the payment method is the default
300
+ if(payment != undefined) {
301
+ if((payment.currentMethod == 'gene_braintree_paypal' && $('paypal-saved-accounts') == undefined) || ($$('#paypal-saved-accounts input:checked[type=radio]').first() != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other')) {
302
+
303
+ // Verify that vzero is defined before attempting to use it
304
+ if(typeof vzeroPaypal !== 'undefined') {
305
+
306
+ // Set the amount for the PayPal modal window
307
+ vzeroPaypal.setPricing('<?php echo Mage::getSingleton('checkout/cart')->getQuote()->collectTotals()->getGrandTotal(); ?>', '<?php echo Mage::getSingleton('checkout/cart')->getQuote()->getBaseCurrencyCode(); ?>');
308
+ }
309
+
310
+ addPayPalButton();
311
+ }
312
+ }
313
+
314
+ // Store the original payment method
315
+ var paymentOriginal = Payment.prototype.switchMethod;
316
+
317
+ // Intercept the save function
318
+ Payment.prototype.switchMethod = function (method) {
319
+
320
+ // Detect PayPal choice
321
+ if(method == 'gene_braintree_paypal') {
322
+
323
+ if($('paypal-saved-accounts') == undefined) {
324
+ addPayPalButton();
325
+ } else if($('paypal-saved-accounts') != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first() != undefined && $$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other') {
326
+ addPayPalButton();
327
+ } else {
328
+ hidePayPalButton();
329
+ }
330
+
331
+ } else {
332
+ hidePayPalButton();
333
+ }
334
+
335
+
336
+ // Run the original function
337
+ return paymentOriginal.apply(this, arguments);
338
+
339
+ };
340
+
341
+ // If we have any saved accounts we'll need to do something jammy
342
+ if($$('#paypal-saved-accounts input[type=radio]').first() != undefined) {
343
+
344
+ // Loop through each radio button
345
+ $$('#paypal-saved-accounts input[type=radio]').each(function (savedAccount) {
346
+
347
+ // Observe them changing
348
+ Event.observe(savedAccount, 'click', function (ele) {
349
+ if(savedAccount.value == 'other') {
350
+ addPayPalButton();
351
+ } else {
352
+ hidePayPalButton();
353
+ }
354
+ });
355
+ });
356
+ }
357
+
358
+ // What should happen if the user closes the 3D secure window?
359
+ vzero.close3dSecureMethod(function() {
360
+ stopLoading();
361
+ });
362
+
363
+ // Observe all Ajax requests for changes
364
+ vzero.observeAjaxRequests(function() {
365
+
366
+ // If the method is PayPal remove and re-add the PayPal button
367
+ if(payment.currentMethod == 'gene_braintree_paypal') {
368
+ hidePayPalButton();
369
+ addPayPalButton();
370
+ } else {
371
+ vzero.updateData();
372
+ }
373
+
374
+ });
375
+
376
+ </script>
377
+
378
+ <!-- Fix some minor styling issues with our nested form-list -->
379
+ <style type="text/css">
380
+ #credit-card-form .form-list {
381
+ margin: 10px 0 0 0!important;
382
+ padding: 0!important;
383
+ border: 0!important;
384
+ }
385
+ #credit-card-form .form-list:before, #credit-card-form .form-list:after {
386
+ border: 0!important;
387
+ }
388
+
389
+ #paypal-container {
390
+ float: right;
391
+ }
392
+ #paypal-label {
393
+ line-height: 44px;
394
+ float: right;
395
+ margin-right: 12px;
396
+ }
397
+ #braintree-paypal-button {
398
+ padding: 0!important;
399
+ line-height: unset!important;
400
+ float: left!important;
401
+ }
402
+ </style>
app/design/frontend/base/default/template/gene/braintree/js/setup.phtml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Setup the JavaScript classes with their required fields
4
+ */
5
+ /* @var $this Gene_Braintree_Block_Js */
6
+ ?>
7
+ <script type="text/javascript">
8
+
9
+ // Pass some data over to vZero integration JS
10
+ var vzero = new vZero(
11
+ 'gene_braintree_creditcard',
12
+ '<?php echo $this->getClientToken(); ?>',
13
+ <?php echo $this->is3DEnabled(); ?>,
14
+ false,
15
+ false,
16
+ '<?php echo Mage::getUrl('braintree/checkout/quoteTotal', array('_secure' => Mage::app()->getFrontController()->getRequest()->isSecure())); ?>',
17
+ '<?php echo Mage::getUrl('braintree/checkout/tokenizeCard', array('_secure' => Mage::app()->getFrontController()->getRequest()->isSecure())); ?>'
18
+ );
19
+
20
+ <?php if($this->isPayPalActive()): ?>
21
+
22
+ // Pass some data through to the PayPal integration
23
+ var vzeroPaypal = new vZeroPayPalButton(
24
+ '<?php echo $this->getClientToken(); ?>',
25
+ '<?php echo Mage::app()->getStore()->getFrontendName(); ?>',
26
+ <?php echo $this->getSingleUse(); ?>,
27
+ '<?php echo $this->getLocale(); ?>',
28
+ <?php echo $this->getSingleFutureUse(); ?>
29
+ );
30
+
31
+ <?php endif; ?>
32
+
33
+ // Init the environment
34
+ vzero.init();
35
+
36
+ </script>
app/design/frontend/base/default/template/gene/braintree/paypal.phtml ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Gene_Braintree_Block_Paypal */
3
+ ?>
4
+ <div class="form-list" id="payment_form_<?php echo $this->getMethodCode() ?>" style="display: none;">
5
+
6
+ <?php if($this->hasSavedDetails() && $this->getMethod()->isVaultEnabled()): ?>
7
+
8
+ <label><?php echo $this->__('Linked Accounts'); ?></label>
9
+ <p><?php echo $this->__('The following PayPal accounts are currently linked with your account.'); ?></p>
10
+ <table width="100%" cellspacing="0" cellpadding="0" id="paypal-saved-accounts">
11
+ <?php
12
+ $count = 0;
13
+ foreach($this->getSavedDetails() as $savedDetail):
14
+ ?>
15
+ <tr>
16
+ <td width="20"><input type="radio" name="payment[paypal_payment_method_token]" id="<?php echo $savedDetail->token; ?>" value="<?php echo $savedDetail->token; ?>"<?php echo ($count == 0 ? ' checked="checked"' : ''); ?>/></td>
17
+ <td valign="middle"><label for="<?php echo $savedDetail->token; ?>" style="line-height: 48px;"><img src="<?php echo $this->getSkinUrl('images/gene/braintree/PP.png') ?>" align="left" />&nbsp;&nbsp; <?php echo $savedDetail->email; ?></label></td>
18
+ </tr>
19
+ <?php
20
+ ++$count;
21
+ endforeach; ?>
22
+ <tr>
23
+ <td width="20"><input type="radio" name="payment[paypal_payment_method_token]" id="other-paypal" value="other" /></td>
24
+ <td><label for="other-paypal"><?php echo $this->__('New PayPal Account'); ?></label></td>
25
+ </tr>
26
+ </table>
27
+
28
+ <?php endif; ?>
29
+
30
+ <div class="paypal-info"<?php echo ($this->hasSavedDetails() && $this->getMethod()->isVaultEnabled() ? ' style="display: none;"' : ''); ?>>
31
+ <p><?php echo $this->__('You will complete your payment via PayPal after the order review step.'); ?></p>
32
+
33
+ <?php if($this->canSavePayPal()): ?>
34
+ <input type="checkbox" title="<?php echo $this->__('Save this account for future use') ?>"
35
+ class="input-checkbox" id="gene_braintree_paypal_store_in_vault" name="payment[save_paypal]"
36
+ value="1"/>
37
+ <label for="gene_braintree_paypal_store_in_vault" style="float:none;"><?php echo $this->__(
38
+ 'Save this account for future use'
39
+ ) ?></label>
40
+ <?php endif; ?>
41
+
42
+ <?php /* Our hidden field to store the payment nonce */ ?>
43
+ <input type="hidden" name="payment[payment_method_nonce]" id="paypal-payment-nonce" />
44
+ </div>
45
+
46
+ </div>
47
+
48
+ <!-- Attach an event onto all radio buttons -->
49
+ <script type="text/javascript">
50
+
51
+ // Set a flag to determine whether the PayPal flag is initialized
52
+ var PayPalInit = false;
53
+
54
+ // Wrap our logic in a function so we can init in different ways
55
+ initPayPal = function() {
56
+
57
+ // Verify that vzero is defined before attempting to use it
58
+ if (typeof vzeroPaypal !== 'undefined') {
59
+
60
+ // Yay we're good to go
61
+ PayPalInit = true;
62
+
63
+ // Always set the amount as it's needed within 3D secure requests
64
+ vzeroPaypal.setPricing('<?php echo Mage::getSingleton('checkout/cart')->getQuote()->collectTotals()->getGrandTotal(); ?>', '<?php echo Mage::getSingleton('checkout/cart')->getQuote()->getQuoteCurrencyCode(); ?>');
65
+ }
66
+
67
+ $$('#paypal-saved-accounts input[type="radio"]').each(function(elm) {
68
+ Element.observe(elm, 'change', function(event) {
69
+
70
+ // Has the user selected other?
71
+ if($$('#paypal-saved-accounts input:checked[type=radio]').first().value == 'other') {
72
+
73
+ // Show the form
74
+ $$('.paypal-info').first().show();
75
+
76
+ // Enable the form
77
+ $$('.paypal-info input, .paypal-info select').each(function(formElement) {
78
+ formElement.removeAttribute('disabled');
79
+ });
80
+
81
+ } else {
82
+
83
+ // Hide the form
84
+ $$('.paypal-info').first().hide();
85
+
86
+ // Disable any form elements within the form
87
+ $$('.paypal-info input, .paypal-info select').each(function(formElement) {
88
+ formElement.setAttribute('disabled', 'disabled');
89
+ });
90
+ }
91
+ });
92
+ });
93
+
94
+ };
95
+
96
+ // Init PayPal on load
97
+ initPayPal();
98
+
99
+ // If the function didn't run on the load of the payment method do it on dom:loaded
100
+ if(!PayPalInit) {
101
+ document.observe('dom:loaded', function () {
102
+ initPayPal();
103
+ });
104
+ }
105
+
106
+ </script>
app/design/frontend/base/default/template/gene/braintree/paypal/info.phtml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p><strong><?php echo $this->escapeHtml($this->getMethod()->getTitle()) ?></strong></p>
2
+
3
+ <?php if ($_specificInfo = $this->getSpecificInformation()):?>
4
+ <table>
5
+ <tbody>
6
+ <?php foreach ($_specificInfo as $_label => $_value):
7
+ if($_value):
8
+ ?>
9
+ <tr>
10
+ <th style="text-align: left;font-weight:bold;padding: 3px 0;"><?php echo $this->escapeHtml($_label)?>:</th>
11
+ </tr>
12
+ <tr>
13
+ <td style="padding: 3px 0;"><?php echo nl2br(implode($this->getValueAsArray($_value, true), "\n"))?></td>
14
+ </tr>
15
+ <?php endif;
16
+ endforeach; ?>
17
+ </tbody>
18
+ </table>
19
+ <?php endif;?>
20
+
21
+ <?php echo $this->getChildHtml()?>
app/etc/modules/Gene_Braintree.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Gene_Braintree>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Gene_Braintree>
8
+ </modules>
9
+ </config>
app/locale/en_US/Gene_Braintree.csv ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Braintree v.zero - Configuration","Braintree v.zero - Configuration"
2
+ "4px 0 8px 0;" border="0"/><br />To use this module you will need an existing production or sandbox Braintree account. You can apply at <a href="https://www.braintreepayments.com">braintreepayments.com</a>.<br />Braintree v.zero integration provided by <a href="http://gene.co.uk/" target="_blank">Gene Commerce</a>.","4px 0 8px 0;" border="0"/><br />To use this module you will need an existing production or sandbox Braintree account. You can apply at <a href="https://www.braintreepayments.com">braintreepayments.com</a>.<br />Braintree v.zero integration provided by <a href="http://gene.co.uk/" target="_blank">Gene Commerce</a>."
3
+ "Braintree PHP SDK Version","Braintree PHP SDK Version"
4
+ "Magento Braintree v.zero Version","Magento Braintree v.zero Version"
5
+ "Braintree Account Details","Braintree Account Details"
6
+ "Environment","Environment"
7
+ "<strong>Warning:</strong> Do not use 'Sandbox' on a production environment.<br />","<strong>Warning:</strong> Do not use 'Sandbox' on a production environment.<br />"
8
+ "Your API details above will need to reflect your Sandbox or your Production account.","Your API details above will need to reflect your Sandbox or your Production account."
9
+ "Sandbox","Sandbox"
10
+ "Production","Production"
11
+ "Merchant ID","Merchant ID"
12
+ "Merchant Account ID","Merchant Account ID"
13
+ "Public Key","Public Key"
14
+ "Private Key","Private Key"
15
+ "Testing Settings","Testing Settings"
16
+ "Debug","Debug"
17
+ "Debugging will cause a log to be written to the <strong>var/log/gene_braintree.log</strong> file. As no credit card data ever hits the server this file will never contain any crucial customer information.","Debugging will cause a log to be written to the <strong>var/log/gene_braintree.log</strong> file. As no credit card data ever hits the server this file will never contain any crucial customer information."
18
+ "Braintree v.zero - PayPal","Braintree v.zero - PayPal"
19
+ "6px 0;" /><br />You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details.","6px 0;" /><br />You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details."
20
+ "Enabled","Enabled"
21
+ "Title","Title"
22
+ "Capture","Capture"
23
+ "Complete Order Status","Complete Order Status"
24
+ "Features","Features"
25
+ "Payment Type","Payment Type"
26
+ "<strong>Single Payment</strong> - Will only require the customer to sign in, we will only be able to take a single payment<br />","<strong>Single Payment</strong> - Will only require the customer to sign in, we will only be able to take a single payment<br />"
27
+ "<strong>Future Payments</strong> - Allows us to save the customers PayPal account for later purchases and use with the Vault","<strong>Future Payments</strong> - Allows us to save the customers PayPal account for later purchases and use with the Vault"
28
+ "Single Payment","Single Payment"
29
+ "Future Payments","Future Payments"
30
+ "Enable Vault","Enable Vault"
31
+ "Storing the customers PayPal in the vault will allow them to instantly purchase any product without having to login to PayPal again.","Storing the customers PayPal in the vault will allow them to instantly purchase any product without having to login to PayPal again."
32
+ "Locale","Locale"
33
+ "The locale for the PayPal popup window","The locale for the PayPal popup window"
34
+ "Australia","Australia"
35
+ "Canada","Canada"
36
+ "France","France"
37
+ "Germany","Germany"
38
+ "Great Britain & Ireland","Great Britain & Ireland"
39
+ "Hong Kong","Hong Kong"
40
+ "Italy","Italy"
41
+ "Spain","Spain"
42
+ "United States","United States"
43
+ "Display","Display"
44
+ "Sort Order","Sort Order"
45
+ "Braintree v.zero - Credit Card","Braintree v.zero - Credit Card"
46
+ "You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details.","You must first configure the <strong>Braintree v.zero - Configuration</strong> section with your Braintree account details."
47
+ "Payment Action","Payment Action"
48
+ "<strong>Authorize</strong> - Will only auth the payment and store a token, the transaction will not be settled.<br />","<strong>Authorize</strong> - Will only auth the payment and store a token, the transaction will not be settled.<br />"
49
+ "<strong>Authorize & Capture</strong> - We will instantly settle the transaction within the checkout.","<strong>Authorize & Capture</strong> - We will instantly settle the transaction within the checkout."
50
+ "Authorize","Authorize"
51
+ "Authorize & Capture","Authorize & Capture"
52
+ "Capture Action","Capture Action"
53
+ "If you're just authorizing transactions you can define at what point they should be submitted for settlement.","If you're just authorizing transactions you can define at what point they should be submitted for settlement."
54
+ "Invoice","Invoice"
55
+ "Shipment","Shipment"
56
+ "New Order Status","New Order Status"
57
+ "Enable Vault/Saved Cards","Enable Vault/Saved Cards"
58
+ "The vault allows you to securely store the customers credit card on Braintree's servers. We're provided with a token which allows the customer to make future payments without having to enter any details again.","The vault allows you to securely store the customers credit card on Braintree's servers. We're provided with a token which allows the customer to make future payments without having to enter any details again."
59
+ "Enable 3D Secure","Enable 3D Secure"
60
+ "The 3D Secure feature enables the shopper to enter a password to confirm their identity with the card issuer. If accepted they then complete their order, and when received by you, you have much more confidence that is genuine and real.","The 3D Secure feature enables the shopper to enter a password to confirm their identity with the card issuer. If accepted they then complete their order, and when received by you, you have much more confidence that is genuine and real."
61
+ "CVV Verification","CVV Verification"
62
+ "Should we verify the CVV against the card?","Should we verify the CVV against the card?"
63
+ "Kount Merchant ID","Kount Merchant ID"
64
+ "Braintree offers a direct integration with Kount, our partner for providing advanced fraud detection technology. To use this feature, you must be processing at least 2500 transactions per month, and you’ll be subject to additional fees from Kount for their services. To get started, contact accounts@braintreepayments.com. You can view more information <a href="https://developers.braintreepayments.com/javascript+php/guides/fraud-tools">here</a>.","Braintree offers a direct integration with Kount, our partner for providing advanced fraud detection technology. To use this feature, you must be processing at least 2500 transactions per month, and you’ll be subject to additional fees from Kount for their services. To get started, contact accounts@braintreepayments.com. You can view more information <a href="https://developers.braintreepayments.com/javascript+php/guides/fraud-tools">here</a>."
65
+ "Credit Card Types","Credit Card Types"
66
+ "Payment from Applicable Countries","Payment from Applicable Countries"
67
+ "Payment from Specific Countries","Payment from Specific Countries"
68
+ "Braintree Transactions","Braintree Transactions"
69
+ "Valid Credentials","Valid Credentials"
70
+ "You're ready to accept payments via Braintree","You're ready to accept payments via Braintree"
71
+ "Authorization Expired","Authorization Expired"
72
+ "Authorizing","Authorizing"
73
+ "Authorized","Authorized"
74
+ "Gateway Rejected","Gateway Rejected"
75
+ "Failed","Failed"
76
+ "Processor Declined","Processor Declined"
77
+ "Settled","Settled"
78
+ "Settling","Settling"
79
+ "Submitted For Settlement","Submitted For Settlement"
80
+ "Voided","Voided"
81
+ "Unrecognized","Unrecognized"
82
+ "Settlement Declined","Settlement Declined"
83
+ "Settlement Pending","Settlement Pending"
84
+ "ID","ID"
85
+ "Transaction Date","Transaction Date"
86
+ "Magento Order ID","Magento Order ID"
87
+ "Magento Status","Magento Status"
88
+ "Type","Type"
89
+ "Payment Information","Payment Information"
90
+ "Amount","Amount"
91
+ "Currency","Currency"
92
+ "Braintree Status","Braintree Status"
93
+ "CSV","CSV"
94
+ "Excel XML","Excel XML"
95
+ "Your card payment has failed, please try again.","Your card payment has failed, please try again."
96
+ "We require a CVV when creating card transactions.","We require a CVV when creating card transactions."
97
+ "There was an issue whilst trying to process your card payment, please try again or another method.","There was an issue whilst trying to process your card payment, please try again or another method."
98
+ "Your transaction has been declined, please try another payment method or contacting your issuing bank.","Your transaction has been declined, please try another payment method or contacting your issuing bank."
99
+ "%s. Please try again or attempt refreshing the page.","%s. Please try again or attempt refreshing the page."
100
+ "Your 3D secure verification has failed, please try using another card, or payment method.","Your 3D secure verification has failed, please try using another card, or payment method."
101
+ "There has been an issue processing your PayPal payment, please try again.","There has been an issue processing your PayPal payment, please try again."
102
+ "We were unable to complete your purchase through PayPal, please try again or an alternative payment method.","We were unable to complete your purchase through PayPal, please try again or an alternative payment method."
103
+ "The following PayPal accounts are currently linked with your account.","The following PayPal accounts are currently linked with your account."
104
+ "The following credit cards accounts are currently linked with your account.","The following credit cards accounts are currently linked with your account."
105
+ "You will complete your payment via PayPal after the order review step.","You will complete your payment via PayPal after the order review step."
106
+ "You're able to use any of the listed payment methods below when purchasing through our checkout, you're able to add new payment methods within the checkout.","You're able to use any of the listed payment methods below when purchasing through our checkout, you're able to add new payment methods within the checkout."
107
+ "You currently have no saved payment information, you can save a payment method when making a purchase.","You currently have no saved payment information, you can save a payment method when making a purchase."
108
+ "Saved Payment Information","Saved Payment Information"
109
+ "Save this account for future use","Save this account for future use"
110
+ "Complete checkout with","Complete checkout with"
111
+ "Are you sure you want to remove this payment method?","Are you sure you want to remove this payment method?"
112
+ "Saved Cards","Saved Cards"
113
+ "Expires:","Expires:"
114
+ "New Credit Card","New Credit Card"
115
+ "Credit Card Number","Credit Card Number"
116
+ "Expiration Date","Expiration Date"
117
+ "Card Verification Number","Card Verification Number"
118
+ "Save this card for future use","Save this card for future use"
119
+ "Sadly, we're unable to accept this type of card, please try another.","Sadly, we're unable to accept this type of card, please try another."
120
+ "We cannot detect the card type for this card number, please try re-entering your card details.","We cannot detect the card type for this card number, please try re-entering your card details."
121
+ "We cannot match this card number to any of our accepted payment methods, please try re-entering your details.","We cannot match this card number to any of our accepted payment methods, please try re-entering your details."
js/gene/braintree/braintree.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ !function(){function t(e,n){e instanceof t?(this.enc=e.enc,this.pos=e.pos):(this.enc=e,this.pos=n)}function e(t,e,n,i,r){this.stream=t,this.header=e,this.length=n,this.tag=i,this.sub=r}function n(t){var e,n,i="";for(e=0;e+3<=t.length;e+=3)n=parseInt(t.substring(e,e+3),16),i+=ee.charAt(n>>6)+ee.charAt(63&n);for(e+1==t.length?(n=parseInt(t.substring(e,e+1),16),i+=ee.charAt(n<<2)):e+2==t.length&&(n=parseInt(t.substring(e,e+2),16),i+=ee.charAt(n>>2)+ee.charAt((3&n)<<4));(3&i.length)>0;)i+=ne;return i}function i(t){var e,n,i,r="",o=0;for(e=0;e<t.length&&t.charAt(e)!=ne;++e)i=ee.indexOf(t.charAt(e)),0>i||(0==o?(r+=l(i>>2),n=3&i,o=1):1==o?(r+=l(n<<2|i>>4),n=15&i,o=2):2==o?(r+=l(n),r+=l(i>>2),n=3&i,o=3):(r+=l(n<<2|i>>4),r+=l(15&i),o=0));return 1==o&&(r+=l(n<<2)),r}function r(t){var e,n=i(t),r=new Array;for(e=0;2*e<n.length;++e)r[e]=parseInt(n.substring(2*e,2*e+2),16);return r}function o(t,e,n){null!=t&&("number"==typeof t?this.fromNumber(t,e,n):null==e&&"string"!=typeof t?this.fromString(t,256):this.fromString(t,e))}function s(){return new o(null)}function a(t,e,n,i,r,o){for(;--o>=0;){var s=e*this[t++]+n[i]+r;r=Math.floor(s/67108864),n[i++]=67108863&s}return r}function u(t,e,n,i,r,o){for(var s=32767&e,a=e>>15;--o>=0;){var u=32767&this[t],c=this[t++]>>15,l=a*u+c*s;u=s*u+((32767&l)<<15)+n[i]+(1073741823&r),r=(u>>>30)+(l>>>15)+a*c+(r>>>30),n[i++]=1073741823&u}return r}function c(t,e,n,i,r,o){for(var s=16383&e,a=e>>14;--o>=0;){var u=16383&this[t],c=this[t++]>>14,l=a*u+c*s;u=s*u+((16383&l)<<14)+n[i]+r,r=(u>>28)+(l>>14)+a*c,n[i++]=268435455&u}return r}function l(t){return ue.charAt(t)}function p(t,e){var n=ce[t.charCodeAt(e)];return null==n?-1:n}function h(t){for(var e=this.t-1;e>=0;--e)t[e]=this[e];t.t=this.t,t.s=this.s}function d(t){this.t=1,this.s=0>t?-1:0,t>0?this[0]=t:-1>t?this[0]=t+this.DV:this.t=0}function f(t){var e=s();return e.fromInt(t),e}function m(t,e){var n;if(16==e)n=4;else if(8==e)n=3;else if(256==e)n=8;else if(2==e)n=1;else if(32==e)n=5;else{if(4!=e)return void this.fromRadix(t,e);n=2}this.t=0,this.s=0;for(var i=t.length,r=!1,s=0;--i>=0;){var a=8==n?255&t[i]:p(t,i);0>a?"-"==t.charAt(i)&&(r=!0):(r=!1,0==s?this[this.t++]=a:s+n>this.DB?(this[this.t-1]|=(a&(1<<this.DB-s)-1)<<s,this[this.t++]=a>>this.DB-s):this[this.t-1]|=a<<s,s+=n,s>=this.DB&&(s-=this.DB))}8==n&&0!=(128&t[0])&&(this.s=-1,s>0&&(this[this.t-1]|=(1<<this.DB-s)-1<<s)),this.clamp(),r&&o.ZERO.subTo(this,this)}function y(){for(var t=this.s&this.DM;this.t>0&&this[this.t-1]==t;)--this.t}function g(t){if(this.s<0)return"-"+this.negate().toString(t);var e;if(16==t)e=4;else if(8==t)e=3;else if(2==t)e=1;else if(32==t)e=5;else{if(4!=t)return this.toRadix(t);e=2}var n,i=(1<<e)-1,r=!1,o="",s=this.t,a=this.DB-s*this.DB%e;if(s-->0)for(a<this.DB&&(n=this[s]>>a)>0&&(r=!0,o=l(n));s>=0;)e>a?(n=(this[s]&(1<<a)-1)<<e-a,n|=this[--s]>>(a+=this.DB-e)):(n=this[s]>>(a-=e)&i,0>=a&&(a+=this.DB,--s)),n>0&&(r=!0),r&&(o+=l(n));return r?o:"0"}function b(){var t=s();return o.ZERO.subTo(this,t),t}function v(){return this.s<0?this.negate():this}function _(t){var e=this.s-t.s;if(0!=e)return e;var n=this.t;if(e=n-t.t,0!=e)return this.s<0?-e:e;for(;--n>=0;)if(0!=(e=this[n]-t[n]))return e;return 0}function w(t){var e,n=1;return 0!=(e=t>>>16)&&(t=e,n+=16),0!=(e=t>>8)&&(t=e,n+=8),0!=(e=t>>4)&&(t=e,n+=4),0!=(e=t>>2)&&(t=e,n+=2),0!=(e=t>>1)&&(t=e,n+=1),n}function E(){return this.t<=0?0:this.DB*(this.t-1)+w(this[this.t-1]^this.s&this.DM)}function S(t,e){var n;for(n=this.t-1;n>=0;--n)e[n+t]=this[n];for(n=t-1;n>=0;--n)e[n]=0;e.t=this.t+t,e.s=this.s}function C(t,e){for(var n=t;n<this.t;++n)e[n-t]=this[n];e.t=Math.max(this.t-t,0),e.s=this.s}function A(t,e){var n,i=t%this.DB,r=this.DB-i,o=(1<<r)-1,s=Math.floor(t/this.DB),a=this.s<<i&this.DM;for(n=this.t-1;n>=0;--n)e[n+s+1]=this[n]>>r|a,a=(this[n]&o)<<i;for(n=s-1;n>=0;--n)e[n]=0;e[s]=a,e.t=this.t+s+1,e.s=this.s,e.clamp()}function x(t,e){e.s=this.s;var n=Math.floor(t/this.DB);if(n>=this.t)return void(e.t=0);var i=t%this.DB,r=this.DB-i,o=(1<<i)-1;e[0]=this[n]>>i;for(var s=n+1;s<this.t;++s)e[s-n-1]|=(this[s]&o)<<r,e[s-n]=this[s]>>i;i>0&&(e[this.t-n-1]|=(this.s&o)<<r),e.t=this.t-n,e.clamp()}function T(t,e){for(var n=0,i=0,r=Math.min(t.t,this.t);r>n;)i+=this[n]-t[n],e[n++]=i&this.DM,i>>=this.DB;if(t.t<this.t){for(i-=t.s;n<this.t;)i+=this[n],e[n++]=i&this.DM,i>>=this.DB;i+=this.s}else{for(i+=this.s;n<t.t;)i-=t[n],e[n++]=i&this.DM,i>>=this.DB;i-=t.s}e.s=0>i?-1:0,-1>i?e[n++]=this.DV+i:i>0&&(e[n++]=i),e.t=n,e.clamp()}function k(t,e){var n=this.abs(),i=t.abs(),r=n.t;for(e.t=r+i.t;--r>=0;)e[r]=0;for(r=0;r<i.t;++r)e[r+n.t]=n.am(0,i[r],e,r,0,n.t);e.s=0,e.clamp(),this.s!=t.s&&o.ZERO.subTo(e,e)}function P(t){for(var e=this.abs(),n=t.t=2*e.t;--n>=0;)t[n]=0;for(n=0;n<e.t-1;++n){var i=e.am(n,e[n],t,2*n,0,1);(t[n+e.t]+=e.am(n+1,2*e[n],t,2*n+1,i,e.t-n-1))>=e.DV&&(t[n+e.t]-=e.DV,t[n+e.t+1]=1)}t.t>0&&(t[t.t-1]+=e.am(n,e[n],t,2*n,0,1)),t.s=0,t.clamp()}function I(t,e,n){var i=t.abs();if(!(i.t<=0)){var r=this.abs();if(r.t<i.t)return null!=e&&e.fromInt(0),void(null!=n&&this.copyTo(n));null==n&&(n=s());var a=s(),u=this.s,c=t.s,l=this.DB-w(i[i.t-1]);l>0?(i.lShiftTo(l,a),r.lShiftTo(l,n)):(i.copyTo(a),r.copyTo(n));var p=a.t,h=a[p-1];if(0!=h){var d=h*(1<<this.F1)+(p>1?a[p-2]>>this.F2:0),f=this.FV/d,m=(1<<this.F1)/d,y=1<<this.F2,g=n.t,b=g-p,v=null==e?s():e;for(a.dlShiftTo(b,v),n.compareTo(v)>=0&&(n[n.t++]=1,n.subTo(v,n)),o.ONE.dlShiftTo(p,v),v.subTo(a,a);a.t<p;)a[a.t++]=0;for(;--b>=0;){var _=n[--g]==h?this.DM:Math.floor(n[g]*f+(n[g-1]+y)*m);if((n[g]+=a.am(0,_,n,b,0,p))<_)for(a.dlShiftTo(b,v),n.subTo(v,n);n[g]<--_;)n.subTo(v,n)}null!=e&&(n.drShiftTo(p,e),u!=c&&o.ZERO.subTo(e,e)),n.t=p,n.clamp(),l>0&&n.rShiftTo(l,n),0>u&&o.ZERO.subTo(n,n)}}}function O(t){var e=s();return this.abs().divRemTo(t,null,e),this.s<0&&e.compareTo(o.ZERO)>0&&t.subTo(e,e),e}function U(t){this.m=t}function R(t){return t.s<0||t.compareTo(this.m)>=0?t.mod(this.m):t}function M(t){return t}function N(t){t.divRemTo(this.m,null,t)}function D(t,e,n){t.multiplyTo(e,n),this.reduce(n)}function F(t,e){t.squareTo(e),this.reduce(e)}function L(){if(this.t<1)return 0;var t=this[0];if(0==(1&t))return 0;var e=3&t;return e=e*(2-(15&t)*e)&15,e=e*(2-(255&t)*e)&255,e=e*(2-((65535&t)*e&65535))&65535,e=e*(2-t*e%this.DV)%this.DV,e>0?this.DV-e:-e}function B(t){this.m=t,this.mp=t.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<<t.DB-15)-1,this.mt2=2*t.t}function j(t){var e=s();return t.abs().dlShiftTo(this.m.t,e),e.divRemTo(this.m,null,e),t.s<0&&e.compareTo(o.ZERO)>0&&this.m.subTo(e,e),e}function z(t){var e=s();return t.copyTo(e),this.reduce(e),e}function V(t){for(;t.t<=this.mt2;)t[t.t++]=0;for(var e=0;e<this.m.t;++e){var n=32767&t[e],i=n*this.mpl+((n*this.mph+(t[e]>>15)*this.mpl&this.um)<<15)&t.DM;for(n=e+this.m.t,t[n]+=this.m.am(0,i,t,e,0,this.m.t);t[n]>=t.DV;)t[n]-=t.DV,t[++n]++}t.clamp(),t.drShiftTo(this.m.t,t),t.compareTo(this.m)>=0&&t.subTo(this.m,t)}function H(t,e){t.squareTo(e),this.reduce(e)}function W(t,e,n){t.multiplyTo(e,n),this.reduce(n)}function q(){return 0==(this.t>0?1&this[0]:this.s)}function Q(t,e){if(t>4294967295||1>t)return o.ONE;var n=s(),i=s(),r=e.convert(this),a=w(t)-1;for(r.copyTo(n);--a>=0;)if(e.sqrTo(n,i),(t&1<<a)>0)e.mulTo(i,r,n);else{var u=n;n=i,i=u}return e.revert(n)}function G(t,e){var n;return n=256>t||e.isEven()?new U(e):new B(e),this.exp(t,n)}function Y(t,e){return new o(t,e)}function J(t,e){if(e<t.length+11)throw new Error("Message too long for RSA");for(var n=new Array,i=t.length-1;i>=0&&e>0;){var r=t.charCodeAt(i--);128>r?n[--e]=r:r>127&&2048>r?(n[--e]=63&r|128,n[--e]=r>>6|192):(n[--e]=63&r|128,n[--e]=r>>6&63|128,n[--e]=r>>12|224)}n[--e]=0;for(var s=0,a=0,u=0;e>2;)0==u&&(a=le.random.randomWords(1,0)[0]),s=a>>u&255,u=(u+8)%32,0!=s&&(n[--e]=s);return n[--e]=2,n[--e]=0,new o(n)}function Z(){this.n=null,this.e=0,this.d=null,this.p=null,this.q=null,this.dmp1=null,this.dmq1=null,this.coeff=null}function K(t,e){if(!(null!=t&&null!=e&&t.length>0&&e.length>0))throw new Error("Invalid RSA public key");this.n=Y(t,16),this.e=parseInt(e,16)}function X(t){return t.modPowInt(this.e,this.n)}function $(t){var e=J(t,this.n.bitLength()+7>>3);if(null==e)return null;var n=this.doPublic(e);if(null==n)return null;var i=n.toString(16);return 0==(1&i.length)?i:"0"+i}t.prototype.get=function(t){if(void 0==t&&(t=this.pos++),t>=this.enc.length)throw"Requesting byte offset "+t+" on a stream of length "+this.enc.length;return this.enc[t]},t.prototype.hexDigits="0123456789ABCDEF",t.prototype.hexByte=function(t){return this.hexDigits.charAt(t>>4&15)+this.hexDigits.charAt(15&t)},t.prototype.hexDump=function(t,e){for(var n="",i=t;e>i;++i)switch(n+=this.hexByte(this.get(i)),15&i){case 7:n+=" ";break;case 15:n+="\n";break;default:n+=" "}return n},t.prototype.parseStringISO=function(t,e){for(var n="",i=t;e>i;++i)n+=String.fromCharCode(this.get(i));return n},t.prototype.parseStringUTF=function(t,e){for(var n="",i=0,r=t;e>r;){var i=this.get(r++);n+=String.fromCharCode(128>i?i:i>191&&224>i?(31&i)<<6|63&this.get(r++):(15&i)<<12|(63&this.get(r++))<<6|63&this.get(r++))}return n},t.prototype.reTime=/^((?:1[89]|2\d)?\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/,t.prototype.parseTime=function(t,e){var n=this.parseStringISO(t,e),i=this.reTime.exec(n);return i?(n=i[1]+"-"+i[2]+"-"+i[3]+" "+i[4],i[5]&&(n+=":"+i[5],i[6]&&(n+=":"+i[6],i[7]&&(n+="."+i[7]))),i[8]&&(n+=" UTC","Z"!=i[8]&&(n+=i[8],i[9]&&(n+=":"+i[9]))),n):"Unrecognized time: "+n},t.prototype.parseInteger=function(t,e){var n=e-t;if(n>4){n<<=3;var i=this.get(t);if(0==i)n-=8;else for(;128>i;)i<<=1,--n;return"("+n+" bit)"}for(var r=0,o=t;e>o;++o)r=r<<8|this.get(o);return r},t.prototype.parseBitString=function(t,e){var n=this.get(t),i=(e-t-1<<3)-n,r="("+i+" bit)";if(20>=i){var o=n;r+=" ";for(var s=e-1;s>t;--s){for(var a=this.get(s),u=o;8>u;++u)r+=a>>u&1?"1":"0";o=0}}return r},t.prototype.parseOctetString=function(t,e){var n=e-t,i="("+n+" byte) ";n>20&&(e=t+20);for(var r=t;e>r;++r)i+=this.hexByte(this.get(r));return n>20&&(i+=String.fromCharCode(8230)),i},t.prototype.parseOID=function(t,e){for(var n,i=0,r=0,o=t;e>o;++o){var s=this.get(o);i=i<<7|127&s,r+=7,128&s||(void 0==n?n=parseInt(i/40)+"."+i%40:n+="."+(r>=31?"bigint":i),i=r=0),n+=String.fromCharCode()}return n},e.prototype.typeName=function(){if(void 0==this.tag)return"unknown";var t=this.tag>>6,e=(this.tag>>5&1,31&this.tag);switch(t){case 0:switch(e){case 0:return"EOC";case 1:return"BOOLEAN";case 2:return"INTEGER";case 3:return"BIT_STRING";case 4:return"OCTET_STRING";case 5:return"NULL";case 6:return"OBJECT_IDENTIFIER";case 7:return"ObjectDescriptor";case 8:return"EXTERNAL";case 9:return"REAL";case 10:return"ENUMERATED";case 11:return"EMBEDDED_PDV";case 12:return"UTF8String";case 16:return"SEQUENCE";case 17:return"SET";case 18:return"NumericString";case 19:return"PrintableString";case 20:return"TeletexString";case 21:return"VideotexString";case 22:return"IA5String";case 23:return"UTCTime";case 24:return"GeneralizedTime";case 25:return"GraphicString";case 26:return"VisibleString";case 27:return"GeneralString";case 28:return"UniversalString";case 30:return"BMPString";default:return"Universal_"+e.toString(16)}case 1:return"Application_"+e.toString(16);case 2:return"["+e+"]";case 3:return"Private_"+e.toString(16)}},e.prototype.content=function(){if(void 0==this.tag)return null;var t=this.tag>>6;if(0!=t)return null==this.sub?null:"("+this.sub.length+")";var e=31&this.tag,n=this.posContent(),i=Math.abs(this.length);switch(e){case 1:return 0==this.stream.get(n)?"false":"true";case 2:return this.stream.parseInteger(n,n+i);case 3:return this.sub?"("+this.sub.length+" elem)":this.stream.parseBitString(n,n+i);case 4:return this.sub?"("+this.sub.length+" elem)":this.stream.parseOctetString(n,n+i);case 6:return this.stream.parseOID(n,n+i);case 16:case 17:return"("+this.sub.length+" elem)";case 12:return this.stream.parseStringUTF(n,n+i);case 18:case 19:case 20:case 21:case 22:case 26:return this.stream.parseStringISO(n,n+i);case 23:case 24:return this.stream.parseTime(n,n+i)}return null},e.prototype.toString=function(){return this.typeName()+"@"+this.stream.pos+"[header:"+this.header+",length:"+this.length+",sub:"+(null==this.sub?"null":this.sub.length)+"]"},e.prototype.print=function(t){if(void 0==t&&(t=""),document.writeln(t+this),null!=this.sub){t+=" ";for(var e=0,n=this.sub.length;n>e;++e)this.sub[e].print(t)}},e.prototype.toPrettyString=function(t){void 0==t&&(t="");var e=t+this.typeName()+" @"+this.stream.pos;if(this.length>=0&&(e+="+"),e+=this.length,32&this.tag?e+=" (constructed)":3!=this.tag&&4!=this.tag||null==this.sub||(e+=" (encapsulates)"),e+="\n",null!=this.sub){t+=" ";for(var n=0,i=this.sub.length;i>n;++n)e+=this.sub[n].toPrettyString(t)}return e},e.prototype.posStart=function(){return this.stream.pos},e.prototype.posContent=function(){return this.stream.pos+this.header},e.prototype.posEnd=function(){return this.stream.pos+this.header+Math.abs(this.length)},e.decodeLength=function(t){var e=t.get(),n=127&e;if(n==e)return n;if(n>3)throw"Length over 24 bits not supported at position "+(t.pos-1);if(0==n)return-1;e=0;for(var i=0;n>i;++i)e=e<<8|t.get();return e},e.hasContent=function(n,i,r){if(32&n)return!0;if(3>n||n>4)return!1;var o=new t(r);3==n&&o.get();var s=o.get();if(s>>6&1)return!1;try{var a=e.decodeLength(o);return o.pos-r.pos+a==i}catch(u){return!1}},e.decode=function(n){n instanceof t||(n=new t(n,0));var i=new t(n),r=n.get(),o=e.decodeLength(n),s=n.pos-i.pos,a=null;if(e.hasContent(r,o,n)){var u=n.pos;if(3==r&&n.get(),a=[],o>=0){for(var c=u+o;n.pos<c;)a[a.length]=e.decode(n);if(n.pos!=c)throw"Content size is not correct for container starting at offset "+u}else try{for(;;){var l=e.decode(n);if(0==l.tag)break;a[a.length]=l}o=u-n.pos}catch(p){throw"Exception while decoding undefined length content: "+p}}else n.pos+=o;return new e(i,s,o,r,a)};var te,ee="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",ne="=",ie=0xdeadbeefcafe,re=15715070==(16777215&ie);re&&"Microsoft Internet Explorer"==navigator.appName?(o.prototype.am=u,te=30):re&&"Netscape"!=navigator.appName?(o.prototype.am=a,te=26):(o.prototype.am=c,te=28),o.prototype.DB=te,o.prototype.DM=(1<<te)-1,o.prototype.DV=1<<te;var oe=52;o.prototype.FV=Math.pow(2,oe),o.prototype.F1=oe-te,o.prototype.F2=2*te-oe;var se,ae,ue="0123456789abcdefghijklmnopqrstuvwxyz",ce=new Array;for(se="0".charCodeAt(0),ae=0;9>=ae;++ae)ce[se++]=ae;for(se="a".charCodeAt(0),ae=10;36>ae;++ae)ce[se++]=ae;for(se="A".charCodeAt(0),ae=10;36>ae;++ae)ce[se++]=ae;U.prototype.convert=R,U.prototype.revert=M,U.prototype.reduce=N,U.prototype.mulTo=D,U.prototype.sqrTo=F,B.prototype.convert=j,B.prototype.revert=z,B.prototype.reduce=V,B.prototype.mulTo=W,B.prototype.sqrTo=H,o.prototype.copyTo=h,o.prototype.fromInt=d,o.prototype.fromString=m,o.prototype.clamp=y,o.prototype.dlShiftTo=S,o.prototype.drShiftTo=C,o.prototype.lShiftTo=A,o.prototype.rShiftTo=x,o.prototype.subTo=T,o.prototype.multiplyTo=k,o.prototype.squareTo=P,o.prototype.divRemTo=I,o.prototype.invDigit=L,o.prototype.isEven=q,o.prototype.exp=Q,o.prototype.toString=g,o.prototype.negate=b,o.prototype.abs=v,o.prototype.compareTo=_,o.prototype.bitLength=E,o.prototype.mod=O,o.prototype.modPowInt=G,o.ZERO=f(0),o.ONE=f(1),Z.prototype.doPublic=X,Z.prototype.setPublic=K,Z.prototype.encrypt=$;var le={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(t){this.toString=function(){return"CORRUPT: "+this.message},this.message=t},invalid:function(t){this.toString=function(){return"INVALID: "+this.message},this.message=t},bug:function(t){this.toString=function(){return"BUG: "+this.message},this.message=t},notReady:function(t){this.toString=function(){return"NOT READY: "+this.message},this.message=t}}};"undefined"!=typeof module&&module.exports&&(module.exports=le),le.cipher.aes=function(t){this._tables[0][0][0]||this._precompute();var e,n,i,r,o,s=this._tables[0][4],a=this._tables[1],u=t.length,c=1;if(4!==u&&6!==u&&8!==u)throw new le.exception.invalid("invalid aes key size");for(this._key=[r=t.slice(0),o=[]],e=u;4*u+28>e;e++)i=r[e-1],(e%u===0||8===u&&e%u===4)&&(i=s[i>>>24]<<24^s[i>>16&255]<<16^s[i>>8&255]<<8^s[255&i],e%u===0&&(i=i<<8^i>>>24^c<<24,c=c<<1^283*(c>>7))),r[e]=r[e-u]^i;for(n=0;e;n++,e--)i=r[3&n?e:e-4],o[n]=4>=e||4>n?i:a[0][s[i>>>24]]^a[1][s[i>>16&255]]^a[2][s[i>>8&255]]^a[3][s[255&i]]},le.cipher.aes.prototype={encrypt:function(t){return this._crypt(t,0)},decrypt:function(t){return this._crypt(t,1)},_tables:[[[],[],[],[],[]],[[],[],[],[],[]]],_precompute:function(){var t,e,n,i,r,o,s,a,u,c=this._tables[0],l=this._tables[1],p=c[4],h=l[4],d=[],f=[];for(t=0;256>t;t++)f[(d[t]=t<<1^283*(t>>7))^t]=t;for(e=n=0;!p[e];e^=i||1,n=f[n]||1)for(s=n^n<<1^n<<2^n<<3^n<<4,s=s>>8^255&s^99,p[e]=s,h[s]=e,o=d[r=d[i=d[e]]],u=16843009*o^65537*r^257*i^16843008*e,a=257*d[s]^16843008*s,t=0;4>t;t++)c[t][e]=a=a<<24^a>>>8,l[t][s]=u=u<<24^u>>>8;for(t=0;5>t;t++)c[t]=c[t].slice(0),l[t]=l[t].slice(0)},_crypt:function(t,e){if(4!==t.length)throw new le.exception.invalid("invalid aes block size");var n,i,r,o,s=this._key[e],a=t[0]^s[0],u=t[e?3:1]^s[1],c=t[2]^s[2],l=t[e?1:3]^s[3],p=s.length/4-2,h=4,d=[0,0,0,0],f=this._tables[e],m=f[0],y=f[1],g=f[2],b=f[3],v=f[4];for(o=0;p>o;o++)n=m[a>>>24]^y[u>>16&255]^g[c>>8&255]^b[255&l]^s[h],i=m[u>>>24]^y[c>>16&255]^g[l>>8&255]^b[255&a]^s[h+1],r=m[c>>>24]^y[l>>16&255]^g[a>>8&255]^b[255&u]^s[h+2],l=m[l>>>24]^y[a>>16&255]^g[u>>8&255]^b[255&c]^s[h+3],h+=4,a=n,u=i,c=r;for(o=0;4>o;o++)d[e?3&-o:o]=v[a>>>24]<<24^v[u>>16&255]<<16^v[c>>8&255]<<8^v[255&l]^s[h++],n=a,a=u,u=c,c=l,l=n;return d}},le.bitArray={bitSlice:function(t,e,n){return t=le.bitArray._shiftRight(t.slice(e/32),32-(31&e)).slice(1),void 0===n?t:le.bitArray.clamp(t,n-e)},extract:function(t,e,n){var i,r=Math.floor(-e-n&31);return i=-32&(e+n-1^e)?t[e/32|0]<<32-r^t[e/32+1|0]>>>r:t[e/32|0]>>>r,i&(1<<n)-1},concat:function(t,e){if(0===t.length||0===e.length)return t.concat(e);var n=t[t.length-1],i=le.bitArray.getPartial(n);return 32===i?t.concat(e):le.bitArray._shiftRight(e,i,0|n,t.slice(0,t.length-1))},bitLength:function(t){var e,n=t.length;return 0===n?0:(e=t[n-1],32*(n-1)+le.bitArray.getPartial(e))},clamp:function(t,e){if(32*t.length<e)return t;t=t.slice(0,Math.ceil(e/32));var n=t.length;return e=31&e,n>0&&e&&(t[n-1]=le.bitArray.partial(e,t[n-1]&2147483648>>e-1,1)),t},partial:function(t,e,n){return 32===t?e:(n?0|e:e<<32-t)+1099511627776*t},getPartial:function(t){return Math.round(t/1099511627776)||32},equal:function(t,e){if(le.bitArray.bitLength(t)!==le.bitArray.bitLength(e))return!1;var n,i=0;for(n=0;n<t.length;n++)i|=t[n]^e[n];return 0===i},_shiftRight:function(t,e,n,i){var r,o,s=0;for(void 0===i&&(i=[]);e>=32;e-=32)i.push(n),n=0;if(0===e)return i.concat(t);for(r=0;r<t.length;r++)i.push(n|t[r]>>>e),n=t[r]<<32-e;return s=t.length?t[t.length-1]:0,o=le.bitArray.getPartial(s),i.push(le.bitArray.partial(e+o&31,e+o>32?n:i.pop(),1)),i},_xor4:function(t,e){return[t[0]^e[0],t[1]^e[1],t[2]^e[2],t[3]^e[3]]}},le.codec.hex={fromBits:function(t){var e,n="";for(e=0;e<t.length;e++)n+=((0|t[e])+0xf00000000000).toString(16).substr(4);return n.substr(0,le.bitArray.bitLength(t)/4)},toBits:function(t){var e,n,i=[];for(t=t.replace(/\s|0x/g,""),n=t.length,t+="00000000",e=0;e<t.length;e+=8)i.push(0^parseInt(t.substr(e,8),16));return le.bitArray.clamp(i,4*n)}},le.codec.utf8String={fromBits:function(t){var e,n,i="",r=le.bitArray.bitLength(t);for(e=0;r/8>e;e++)0===(3&e)&&(n=t[e/4]),i+=String.fromCharCode(n>>>24),n<<=8;return decodeURIComponent(escape(i))},toBits:function(t){t=unescape(encodeURIComponent(t));var e,n=[],i=0;for(e=0;e<t.length;e++)i=i<<8|t.charCodeAt(e),3===(3&e)&&(n.push(i),i=0);return 3&e&&n.push(le.bitArray.partial(8*(3&e),i)),n}},le.codec.base64={_chars:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(t,e,n){var i,r="",o=0,s=le.codec.base64._chars,a=0,u=le.bitArray.bitLength(t);for(n&&(s=s.substr(0,62)+"-_"),i=0;6*r.length<u;)r+=s.charAt((a^t[i]>>>o)>>>26),6>o?(a=t[i]<<6-o,o+=26,i++):(a<<=6,o-=6);for(;3&r.length&&!e;)r+="=";return r},toBits:function(t,e){t=t.replace(/\s|=/g,"");var n,i,r=[],o=0,s=le.codec.base64._chars,a=0;for(e&&(s=s.substr(0,62)+"-_"),n=0;n<t.length;n++){if(i=s.indexOf(t.charAt(n)),0>i)throw new le.exception.invalid("this isn't base64!");o>26?(o-=26,r.push(a^i>>>o),a=i<<32-o):(o+=6,a^=i<<32-o)}return 56&o&&r.push(le.bitArray.partial(56&o,a,1)),r}},le.codec.base64url={fromBits:function(t){return le.codec.base64.fromBits(t,1,1)},toBits:function(t){return le.codec.base64.toBits(t,1)}},void 0===le.beware&&(le.beware={}),le.beware["CBC mode is dangerous because it doesn't protect message integrity."]=function(){le.mode.cbc={name:"cbc",encrypt:function(t,e,n,i){if(i&&i.length)throw new le.exception.invalid("cbc can't authenticate data");if(128!==le.bitArray.bitLength(n))throw new le.exception.invalid("cbc iv must be 128 bits");var r,o=le.bitArray,s=o._xor4,a=o.bitLength(e),u=0,c=[];if(7&a)throw new le.exception.invalid("pkcs#5 padding only works for multiples of a byte");for(r=0;a>=u+128;r+=4,u+=128)n=t.encrypt(s(n,e.slice(r,r+4))),c.splice(r,0,n[0],n[1],n[2],n[3]);return a=16843009*(16-(a>>3&15)),n=t.encrypt(s(n,o.concat(e,[a,a,a,a]).slice(r,r+4))),c.splice(r,0,n[0],n[1],n[2],n[3]),c},decrypt:function(t,e,n,i){if(i&&i.length)throw new le.exception.invalid("cbc can't authenticate data");if(128!==le.bitArray.bitLength(n))throw new le.exception.invalid("cbc iv must be 128 bits");if(127&le.bitArray.bitLength(e)||!e.length)throw new le.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");var r,o,s,a=le.bitArray,u=a._xor4,c=[];for(i=i||[],r=0;r<e.length;r+=4)o=e.slice(r,r+4),s=u(n,t.decrypt(o)),c.splice(r,0,s[0],s[1],s[2],s[3]),n=o;if(o=255&c[r-1],0==o||o>16)throw new le.exception.corrupt("pkcs#5 padding corrupt");if(s=16843009*o,!a.equal(a.bitSlice([s,s,s,s],0,8*o),a.bitSlice(c,32*c.length-8*o,32*c.length)))throw new le.exception.corrupt("pkcs#5 padding corrupt");return a.bitSlice(c,0,32*c.length-8*o)}}},le.misc.hmac=function(t,e){this._hash=e=e||le.hash.sha256;var n,i=[[],[]],r=e.prototype.blockSize/32;for(this._baseHash=[new e,new e],t.length>r&&(t=e.hash(t)),n=0;r>n;n++)i[0][n]=909522486^t[n],i[1][n]=1549556828^t[n];this._baseHash[0].update(i[0]),this._baseHash[1].update(i[1])},le.misc.hmac.prototype.encrypt=le.misc.hmac.prototype.mac=function(t,e){var n=new this._hash(this._baseHash[0]).update(t,e).finalize();return new this._hash(this._baseHash[1]).update(n).finalize()},le.hash.sha256=function(t){this._key[0]||this._precompute(),t?(this._h=t._h.slice(0),this._buffer=t._buffer.slice(0),this._length=t._length):this.reset()},le.hash.sha256.hash=function(t){return(new le.hash.sha256).update(t).finalize()},le.hash.sha256.prototype={blockSize:512,reset:function(){return this._h=this._init.slice(0),this._buffer=[],this._length=0,this},update:function(t){"string"==typeof t&&(t=le.codec.utf8String.toBits(t));var e,n=this._buffer=le.bitArray.concat(this._buffer,t),i=this._length,r=this._length=i+le.bitArray.bitLength(t);for(e=512+i&-512;r>=e;e+=512)this._block(n.splice(0,16));return this},finalize:function(){var t,e=this._buffer,n=this._h;for(e=le.bitArray.concat(e,[le.bitArray.partial(1,1)]),t=e.length+2;15&t;t++)e.push(0);for(e.push(Math.floor(this._length/4294967296)),e.push(0|this._length);e.length;)this._block(e.splice(0,16));return this.reset(),n},_init:[],_key:[],_precompute:function(){function t(t){return 4294967296*(t-Math.floor(t))|0}var e,n=0,i=2;t:for(;64>n;i++){for(e=2;i>=e*e;e++)if(i%e===0)continue t;8>n&&(this._init[n]=t(Math.pow(i,.5))),this._key[n]=t(Math.pow(i,1/3)),n++}},_block:function(t){var e,n,i,r,o=t.slice(0),s=this._h,a=this._key,u=s[0],c=s[1],l=s[2],p=s[3],h=s[4],d=s[5],f=s[6],m=s[7];for(e=0;64>e;e++)16>e?n=o[e]:(i=o[e+1&15],r=o[e+14&15],n=o[15&e]=(i>>>7^i>>>18^i>>>3^i<<25^i<<14)+(r>>>17^r>>>19^r>>>10^r<<15^r<<13)+o[15&e]+o[e+9&15]|0),n=n+m+(h>>>6^h>>>11^h>>>25^h<<26^h<<21^h<<7)+(f^h&(d^f))+a[e],m=f,f=d,d=h,h=p+n|0,p=l,l=c,c=u,u=n+(c&l^p&(c^l))+(c>>>2^c>>>13^c>>>22^c<<30^c<<19^c<<10)|0;s[0]=s[0]+u|0,s[1]=s[1]+c|0,s[2]=s[2]+l|0,s[3]=s[3]+p|0,s[4]=s[4]+h|0,s[5]=s[5]+d|0,s[6]=s[6]+f|0,s[7]=s[7]+m|0}},le.random={randomWords:function(t,e){var n,i,r=[],o=this.isReady(e);if(o===this._NOT_READY)throw new le.exception.notReady("generator isn't seeded");for(o&this._REQUIRES_RESEED&&this._reseedFromPools(!(o&this._READY)),n=0;t>n;n+=4)(n+1)%this._MAX_WORDS_PER_BURST===0&&this._gate(),i=this._gen4words(),r.push(i[0],i[1],i[2],i[3]);return this._gate(),r.slice(0,t)},setDefaultParanoia:function(t){this._defaultParanoia=t},addEntropy:function(t,e,n){n=n||"user";var i,r,o,s=(new Date).valueOf(),a=this._robins[n],u=this.isReady(),c=0;switch(i=this._collectorIds[n],void 0===i&&(i=this._collectorIds[n]=this._collectorIdNext++),void 0===a&&(a=this._robins[n]=0),this._robins[n]=(this._robins[n]+1)%this._pools.length,typeof t){case"number":void 0===e&&(e=1),this._pools[a].update([i,this._eventId++,1,e,s,1,0|t]);break;case"object":var l=Object.prototype.toString.call(t);if("[object Uint32Array]"===l){for(o=[],r=0;r<t.length;r++)o.push(t[r]);t=o}else for("[object Array]"!==l&&(c=1),r=0;r<t.length&&!c;r++)"number"!=typeof t[r]&&(c=1);if(!c){if(void 0===e)for(e=0,r=0;r<t.length;r++)for(o=t[r];o>0;)e++,o>>>=1;this._pools[a].update([i,this._eventId++,2,e,s,t.length].concat(t))}break;case"string":void 0===e&&(e=t.length),this._pools[a].update([i,this._eventId++,3,e,s,t.length]),this._pools[a].update(t);break;default:c=1}if(c)throw new le.exception.bug("random: addEntropy only supports number, array of numbers or string");this._poolEntropy[a]+=e,this._poolStrength+=e,u===this._NOT_READY&&(this.isReady()!==this._NOT_READY&&this._fireEvent("seeded",Math.max(this._strength,this._poolStrength)),this._fireEvent("progress",this.getProgress()))},isReady:function(t){var e=this._PARANOIA_LEVELS[void 0!==t?t:this._defaultParanoia];return this._strength&&this._strength>=e?this._poolEntropy[0]>this._BITS_PER_RESEED&&(new Date).valueOf()>this._nextReseed?this._REQUIRES_RESEED|this._READY:this._READY:this._poolStrength>=e?this._REQUIRES_RESEED|this._NOT_READY:this._NOT_READY},getProgress:function(t){var e=this._PARANOIA_LEVELS[t?t:this._defaultParanoia];return this._strength>=e?1:this._poolStrength>e?1:this._poolStrength/e},startCollectors:function(){if(!this._collectorsStarted){if(window.addEventListener)window.addEventListener("load",this._loadTimeCollector,!1),window.addEventListener("mousemove",this._mouseCollector,!1);else{if(!document.attachEvent)throw new le.exception.bug("can't attach event");document.attachEvent("onload",this._loadTimeCollector),document.attachEvent("onmousemove",this._mouseCollector)}this._collectorsStarted=!0}},stopCollectors:function(){this._collectorsStarted&&(window.removeEventListener?(window.removeEventListener("load",this._loadTimeCollector,!1),window.removeEventListener("mousemove",this._mouseCollector,!1)):window.detachEvent&&(window.detachEvent("onload",this._loadTimeCollector),window.detachEvent("onmousemove",this._mouseCollector)),this._collectorsStarted=!1)},addEventListener:function(t,e){this._callbacks[t][this._callbackI++]=e},removeEventListener:function(t,e){var n,i,r=this._callbacks[t],o=[];for(i in r)r.hasOwnProperty(i)&&r[i]===e&&o.push(i);for(n=0;n<o.length;n++)i=o[n],delete r[i]},_pools:[new le.hash.sha256],_poolEntropy:[0],_reseedCount:0,_robins:{},_eventId:0,_collectorIds:{},_collectorIdNext:0,_strength:0,_poolStrength:0,_nextReseed:0,_key:[0,0,0,0,0,0,0,0],_counter:[0,0,0,0],_cipher:void 0,_defaultParanoia:6,_collectorsStarted:!1,_callbacks:{progress:{},seeded:{}},_callbackI:0,_NOT_READY:0,_READY:1,_REQUIRES_RESEED:2,_MAX_WORDS_PER_BURST:65536,_PARANOIA_LEVELS:[0,48,64,96,128,192,256,384,512,768,1024],_MILLISECONDS_PER_RESEED:3e4,_BITS_PER_RESEED:80,_gen4words:function(){for(var t=0;4>t&&(this._counter[t]=this._counter[t]+1|0,!this._counter[t]);t++);return this._cipher.encrypt(this._counter)},_gate:function(){this._key=this._gen4words().concat(this._gen4words()),this._cipher=new le.cipher.aes(this._key)},_reseed:function(t){this._key=le.hash.sha256.hash(this._key.concat(t)),this._cipher=new le.cipher.aes(this._key);for(var e=0;4>e&&(this._counter[e]=this._counter[e]+1|0,!this._counter[e]);e++);},_reseedFromPools:function(t){var e,n=[],i=0;for(this._nextReseed=n[0]=(new Date).valueOf()+this._MILLISECONDS_PER_RESEED,e=0;16>e;e++)n.push(4294967296*Math.random()|0);for(e=0;e<this._pools.length&&(n=n.concat(this._pools[e].finalize()),i+=this._poolEntropy[e],this._poolEntropy[e]=0,t||!(this._reseedCount&1<<e));e++);this._reseedCount>=1<<this._pools.length&&(this._pools.push(new le.hash.sha256),this._poolEntropy.push(0)),this._poolStrength-=i,i>this._strength&&(this._strength=i),this._reseedCount++,this._reseed(n)},_mouseCollector:function(t){var e=t.x||t.clientX||t.offsetX||0,n=t.y||t.clientY||t.offsetY||0;le.random.addEntropy([e,n],2,"mouse")},_loadTimeCollector:function(){le.random.addEntropy((new Date).valueOf(),2,"loadtime")},_fireEvent:function(t,e){var n,i=le.random._callbacks[t],r=[];for(n in i)i.hasOwnProperty(n)&&r.push(i[n]);for(n=0;n<r.length;n++)r[n](e)}},function(){try{var t=new Uint32Array(32);crypto.getRandomValues(t),le.random.addEntropy(t,1024,"crypto.getRandomValues")}catch(e){}}(),function(){for(var t in le.beware)le.beware.hasOwnProperty(t)&&le.beware[t]()}();var pe={sjcl:le,version:"1.3.10"};pe.generateAesKey=function(){return{key:le.random.randomWords(8,0),encrypt:function(t){return this.encryptWithIv(t,le.random.randomWords(4,0))},encryptWithIv:function(t,e){var n=new le.cipher.aes(this.key),i=le.codec.utf8String.toBits(t),r=le.mode.cbc.encrypt(n,i,e),o=le.bitArray.concat(e,r);return le.codec.base64.fromBits(o)}}},pe.create=function(t){return new pe.EncryptionClient(t)},pe.EncryptionClient=function(t){var i=this,o=[];i.publicKey=t,i.version=pe.version;var s=function(t,e){var n,i,r;n=document.createElement(t);for(i in e)e.hasOwnProperty(i)&&(r=e[i],n.setAttribute(i,r));return n},a=function(t){return window.jQuery&&t instanceof jQuery?t[0]:t.nodeType&&1===t.nodeType?t:document.getElementById(t)},u=function(t){var e,n,i,r,o=[];if("INTEGER"===t.typeName()&&(e=t.posContent(),n=t.posEnd(),i=t.stream.hexDump(e,n).replace(/[ \n]/g,""),o.push(i)),null!==t.sub)for(r=0;r<t.sub.length;r++)o=o.concat(u(t.sub[r]));return o},c=function(t){var e,n,i=[],r=t.children;for(n=0;n<r.length;n++)e=r[n],1===e.nodeType&&e.attributes["data-encrypted-name"]?i.push(e):e.children&&e.children.length>0&&(i=i.concat(c(e)));return i},l=function(){var n,i,o,s,a,c;try{a=r(t),n=e.decode(a)}catch(l){throw"Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'"}if(o=u(n),2!==o.length)throw"Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'";return s=o[0],i=o[1],c=new Z,c.setPublic(s,i),c},p=function(){return{key:le.random.randomWords(8,0),sign:function(t){var e=new le.misc.hmac(this.key,le.hash.sha256),n=e.encrypt(t);return le.codec.base64.fromBits(n)}}};i.encrypt=function(t){var e=l(),r=pe.generateAesKey(),o=p(),s=r.encrypt(t),a=o.sign(le.codec.base64.toBits(s)),u=le.bitArray.concat(r.key,o.key),c=le.codec.base64.fromBits(u),h=e.encrypt(c),d="$bt4|javascript_"+i.version.replace(/\./g,"_")+"$",f=null;return h&&(f=n(h)),d+f+"$"+s+"$"+a},i.encryptForm=function(t){var e,n,r,u,l,p;for(t=a(t),p=c(t);o.length>0;){try{t.removeChild(o[0])}catch(h){}o.splice(0,1)}for(l=0;l<p.length;l++)e=p[l],r=e.getAttribute("data-encrypted-name"),n=i.encrypt(e.value),e.removeAttribute("name"),u=s("input",{value:n,type:"hidden",name:r}),o.push(u),t.appendChild(u)},i.onSubmitEncryptForm=function(t,e){var n;t=a(t),n=function(n){return i.encryptForm(t),e?e(n):n},window.jQuery?window.jQuery(t).submit(n):t.addEventListener?t.addEventListener("submit",n,!1):t.attachEvent&&t.attachEvent("onsubmit",n)},i.formEncrypter={encryptForm:i.encryptForm,extractForm:a,onSubmitEncryptForm:i.onSubmitEncryptForm},le.random.startCollectors()},window.Braintree=pe
2
+ }(),!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.braintree=t()}}(function(){var define,module,exports;return function t(e,n,i){function r(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return r(n?n:t)},l,l.exports,t,e,n,i)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s<i.length;s++)r(i[s]);return r}({1:[function(t,e){"use strict";t("./src/rpc-dispatcher")(),e.exports=t("./src/setup.js")},{"./src/rpc-dispatcher":308,"./src/setup.js":309}],2:[function(t,e){(function(n){"use strict";function i(t,e){return t.status>=400?[t,null]:[null,e(t)]}function r(t){var e;this.attrs={},t.hasOwnProperty("sharedCustomerIdentifier")&&(this.attrs.sharedCustomerIdentifier=t.sharedCustomerIdentifier),e=c(t.clientToken),this.driver=t.driver||l,this.authUrl=e.authUrl,this.analyticsUrl=e.analytics?e.analytics.url:void 0,this.clientApiUrl=e.clientApiUrl,this.customerId=t.customerId,this.challenges=e.challenges,this.integration=t.integration||"";var n=u.create(this,{container:t.container,clientToken:e});this.verify3DS=a.bind(n.verify,n),this.attrs.authorizationFingerprint=e.authorizationFingerprint,this.attrs.sharedCustomerIdentifierType=t.sharedCustomerIdentifierType,e.merchantAccountId&&(this.attrs.merchantAccountId=e.merchantAccountId),this.timeoutWatchers=[],this.requestTimeout=t.hasOwnProperty("timeout")?t.timeout:6e4}function o(){}function s(t,e){var n,i={};for(n in t)t.hasOwnProperty(n)&&(i[n]=t[n]);for(n in e)e.hasOwnProperty(n)&&(i[n]=e[n]);return i}var a=t("braintree-utilities"),u=t("braintree-3ds"),c=t("./parse-client-token"),l=t("./jsonp-driver"),p=t("./util"),h=t("./sepa-mandate"),d=t("./sepa-bank-account"),f=t("./credit-card"),m=t("./coinbase-account"),y=t("./root-data"),g=t("./normalize-api-fields").normalizeCreditCardFields;r.prototype.requestWithTimeout=function(t,e,n,r,s){s=s||o;var a,u,c=this;y.get(function(o){u="braintree/web/"+o.sdkVersion,e.braintreeLibraryVersion=u,e.hasOwnProperty("analytics")&&e.hasOwnProperty("_meta")&&(e._meta.sdkVersion=u,e._meta.merchantAppId=o.merchantAppId),a=r(t,e,function(t,e){if(c.timeoutWatchers[e]){clearTimeout(c.timeoutWatchers[e]);var r=i(t,function(t){return n(t)});s.apply(null,r)}}),c.requestTimeout>0?this.timeoutWatchers[a]=setTimeout(function(){c.timeoutWatchers[a]=null,s.apply(null,[{errors:"Unknown error"},null])},c.requestTimeout):s.apply(null,[{errors:"Unknown error"},null])},this)},r.prototype.post=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.post,i)},r.prototype.get=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.get,i)},r.prototype.put=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.put,i)},r.prototype.getCreditCards=function(t){this.get(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods"]),this.attrs,function(t){var e=0,n=t.paymentMethods.length,i=[];for(e;n>e;e++)i.push(new f(t.paymentMethods[e]));return i},t)},r.prototype.tokenizeCoinbase=function(t,e){t.options={validate:!1},this.addCoinbase(t,function(t,n){t?e(t,null):n&&n.nonce?e(t,n):e("Unable to tokenize coinbase account.",null)})},r.prototype.tokenizeCard=function(t,e){t.options={validate:!1},this.addCreditCard(t,function(t,n){n&&n.nonce?e(t,n.nonce,{type:n.type,details:n.details}):e("Unable to tokenize card.",null)})},r.prototype.lookup3DS=function(t,e){var n=p.joinUrlFragments([this.clientApiUrl,"v1/payment_methods",t.nonce,"three_d_secure/lookup"]),i=s(this.attrs,{amount:t.amount});this.post(n,i,function(t){return t},e)},r.prototype.addSEPAMandate=function(t,e){var n=s(this.attrs,{sepaMandate:t});this.post(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates.json"]),n,function(t){return new h(t.sepaMandates[0])},e)},r.prototype.acceptSEPAMandate=function(t,e){this.put(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates",t,"accept"]),this.attrs,function(t){return new d(t.sepaBankAccounts[0])},e)},r.prototype.getSEPAMandate=function(t,e){var n;n=t.paymentMethodToken?s(this.attrs,{paymentMethodToken:t.paymentMethodToken}):this.attrs,this.get(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates",t.mandateReferenceNumber||""]),n,function(t){return new h(t.sepaMandates[0])},e)},r.prototype.addCoinbase=function(t,e){var n;delete t.share,n=s(this.attrs,{coinbaseAccount:t,_meta:{integration:this.integration||"custom",source:"coinbase"}}),this.post(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/coinbase_accounts"]),n,function(t){return new m(t.coinbaseAccounts[0])},e)},r.prototype.addCreditCard=function(t,e){var n,i=t.share;delete t.share;var r=g(t);n=s(this.attrs,{share:i,creditCard:r,_meta:{integration:this.integration||"custom",source:"form"}}),this.post(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/credit_cards"]),n,function(t){return new f(t.creditCards[0])},e)},r.prototype.unlockCreditCard=function(t,e,n){var i=s(this.attrs,{challengeResponses:e});this.put(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/",t.nonce]),i,function(t){return new f(t.paymentMethods[0])},n)},r.prototype.sendAnalyticsEvents=function(t,e){var i,r=this.analyticsUrl,o=[];if(t=p.isArray(t)?t:[t],!r)return void(e&&e.apply(null,[null,{}]));for(var a in t)t.hasOwnProperty(a)&&o.push({kind:t[a]});i=s(this.attrs,{analytics:o,_meta:{platform:"web",platformVersion:n.navigator.userAgent,integrationType:this.integration}}),this.post(r,i,function(t){return t},e)},e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./coinbase-account":3,"./credit-card":4,"./jsonp-driver":5,"./normalize-api-fields":7,"./parse-client-token":8,"./root-data":10,"./sepa-bank-account":11,"./sepa-mandate":12,"./util":13,"braintree-3ds":22,"braintree-utilities":41}],3:[function(t,e){"use strict";function n(t){for(var e=0;e<i.length;e++){var n=i[e];this[n]=t[n]}}var i=["nonce","type","description","details"];e.exports=n},{}],4:[function(t,e){"use strict";function n(t){for(var e=0;e<i.length;e++){var n=i[e];this[n]=t[n]}}var i=["billingAddress","branding","createdAt","createdAtMerchant","createdAtMerchantName","details","isLocked","lastUsedAt","lastUsedAtMerchant","lastUsedAtMerchantName","lastUsedByCurrentMerchant","nonce","securityQuestions","type"];e.exports=n},{}],5:[function(t,e){"use strict";function n(t,e,n){return o.get(t,e,n)}function i(t,e,n){return e._method="POST",o.get(t,e,n)}function r(t,e,n){return e._method="PUT",o.get(t,e,n)}var o=t("./jsonp");e.exports={get:n,post:i,put:r}},{"./jsonp":6}],6:[function(t,e){(function(n){"use strict";function i(t,e){var n=document.createElement("script"),i=!1;n.src=t,n.async=!0;var r=e||l.error;"function"==typeof r&&(n.onerror=function(e){r({url:t,event:e})}),n.onload=n.onreadystatechange=function(){i||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState||(i=!0,n.onload=n.onreadystatechange=null,n&&n.parentNode&&n.parentNode.removeChild(n))},a||(a=document.getElementsByTagName("head")[0]),a.appendChild(n)}function r(t,e){var n,i,o,s=[];for(var o in t)t.hasOwnProperty(o)&&(i=t[o],n=e?u.isArray(t)?e+"[]":e+"["+o+"]":o,s.push("object"==typeof i?r(i,n):encodeURIComponent(n)+"="+encodeURIComponent(i)));return s.join("&")}function o(t,e,n,o){var s=-1===(t||"").indexOf("?")?"?":"&";o=o||l.callbackName||"callback";var a=o+"_json"+u.generateUUID();return s+=r(e),c[a]=function(t){n(t,a);try{delete c[a]}catch(e){}c[a]=null},i(t+s+"&"+o+"="+a),a}function s(t){l=t}var a,u=t("./util"),c=n,l={};e.exports={get:o,init:s,stringify:r}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./util":13}],7:[function(t,e){"use strict";function n(t){var e={billingAddress:t.billingAddress||{}};for(var n in t)if(t.hasOwnProperty(n))switch(n.replace(/_/,"").toLowerCase()){case"postalcode":case"countryname":case"countrycodenumeric":case"countrycodealpha2":case"countrycodealpha3":case"region":case"extendedaddress":case"locality":case"firstname":case"lastname":case"company":case"streetaddress":e.billingAddress[n]=t[n];break;default:e[n]=t[n]}return e}e.exports={normalizeCreditCardFields:n}},{}],8:[function(t,e){"use strict";function n(t){var e;if(!t)throw new Error("Braintree API Client Misconfigured: clientToken required.");if("object"==typeof t&&null!==t)e=t;else{try{t=window.atob(t)}catch(n){}try{e=JSON.parse(t)}catch(i){throw new Error("Braintree API Client Misconfigured: clientToken is invalid.")}}if(!e.hasOwnProperty("authUrl")||!e.hasOwnProperty("clientApiUrl"))throw new Error("Braintree API Client Misconfigured: clientToken is invalid.");return e}t("./polyfill"),e.exports=n},{"./polyfill":9}],9:[function(){(function(t){"use strict";t.atob=t.atob||function(t){var e=new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})([=]{1,2})?$"),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",i="";if(!e.test(t))throw new Error("Braintree API Client Misconfigured: clientToken is invalid.");var r=0;do{var o=n.indexOf(t.charAt(r++)),s=n.indexOf(t.charAt(r++)),a=n.indexOf(t.charAt(r++)),u=n.indexOf(t.charAt(r++)),c=(63&o)<<2|s>>4&3,l=(15&s)<<4|a>>2&15,p=(3&a)<<6|63&u;i+=String.fromCharCode(c)+(l?String.fromCharCode(l):"")+(p?String.fromCharCode(p):"")}while(r<t.length);return i}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],10:[function(t,e){(function(n){"use strict";function i(){var t=n.braintree;return t&&t.hasOwnProperty("VERSION")?t.VERSION:void 0}function r(t,e){null==s?(h.push({callback:t,context:e}),p===!1&&(a=setTimeout(function(){o(d)},200),l.invoke("getExternalData",[],o),p=!0)):t.call(e,s)}function o(t){clearTimeout(a),s={sdkVersion:t.sdkVersion,merchantAppId:t.merchantAppId};for(var e=0;e<h.length;e++){var n=h[e];n.callback.call(n.context,s)}h=[]}var s,a,u=t("braintree-rpc"),c=new u.MessageBus(window),l=new u.RPCClient(c,window.parent),p=!1,h=[],d={sdkVersion:i(),merchantAppId:n.location.href};e.exports={get:r}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"braintree-rpc":30}],11:[function(t,e){"use strict";function n(t){for(var e=0;e<i.length;e++){var n=i[e];this[n]=t[n]}}var i=["bic","maskedIBAN","nonce","accountHolderName"];e.exports=n},{}],12:[function(t,e){"use strict";function n(t){for(var e=0;e<i.length;e++){var n=i[e];this[n]=t[n]}}var i=["accountHolderName","bic","longFormURL","mandateReferenceNumber","maskedIBAN","shortForm"];e.exports=n},{}],13:[function(t,e){"use strict";function n(t){var e,n,i=[];for(n=0;n<t.length;n++)e=t[n],"/"===e.charAt(e.length-1)&&(e=e.substring(0,e.length-1)),"/"===e.charAt(0)&&(e=e.substring(1)),i.push(e);return i.join("/")}function i(t){return t&&"object"==typeof t&&"number"==typeof t.length&&"[object Array]"===Object.prototype.toString.call(t)||!1}function r(){return"xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=Math.floor(16*Math.random()),n="x"===t?e:3&e|8;return n.toString(16)})}e.exports={joinUrlFragments:n,isArray:i,generateUUID:r}},{}],14:[function(t,e){"use strict";function n(t){return new i(t)}var i=t("./lib/client"),r=t("./lib/jsonp"),o=t("./lib/jsonp-driver"),s=t("./lib/util"),a=t("./lib/parse-client-token");e.exports={Client:i,configure:n,util:s,JSONP:r,JSONPDriver:o,parseClientToken:a}},{"./lib/client":2,"./lib/jsonp":6,"./lib/jsonp-driver":5,"./lib/parse-client-token":8,"./lib/util":13}],15:[function(t,e){"use strict";function n(t,e){if(e=e||"["+t+"] is not a valid DOM Element",t&&t.nodeType&&1===t.nodeType)return t;if(t&&window.jQuery&&(t instanceof jQuery||"jquery"in Object(t))&&0!==t.length)return t[0];if("string"==typeof t&&document.getElementById(t))return document.getElementById(t);throw new Error(e)}e.exports={normalizeElement:n}},{}],16:[function(t,e){"use strict";function n(t,e,n,i){t.addEventListener?t.addEventListener(e,n,i):t.attachEvent&&t.attachEvent("on"+e,n)}function i(t,e,n,i){t.removeEventListener?t.removeEventListener(e,n,i):t.detachEvent&&t.detachEvent("on"+e,n)}e.exports={addEventListener:n,removeEventListener:i}},{}],17:[function(t,e){"use strict";function n(t){return"[object Function]"===r.call(t)}function i(t,e){return function(){t.apply(e,arguments)}}var r=Object.prototype.toString;e.exports={bind:i,isFunction:n}},{}],18:[function(t,e){"use strict";function n(){return"https:"===window.location.protocol}function i(t){switch(t){case null:case void 0:return"";case!0:return"1";case!1:return"0";default:return encodeURIComponent(t)}}function r(t,e){var n,o,s=[];for(o in t)if(t.hasOwnProperty(o)){var a=t[o];n=e?e+"["+o+"]":o,"object"==typeof a?s.push(r(a,n)):void 0!==a&&null!==a&&s.push(i(n)+"="+i(a))}return s.join("&")}function o(t){for(var e={},n=t.split("&"),i=0;i<n.length;i++){var r=n[i].split("="),o=r[0],s=decodeURIComponent(r[1]);e[o]=s}return e}function s(t){var e=t.split("?");return 2!==e.length?{}:o(e[1])}e.exports={isBrowserHttps:n,makeQueryString:r,decodeQueryString:o,getParams:s}},{}],19:[function(t,e){var n=t("./lib/dom"),i=t("./lib/url"),r=t("./lib/fn"),o=t("./lib/events");e.exports={normalizeElement:n.normalizeElement,isBrowserHttps:i.isBrowserHttps,makeQueryString:i.makeQueryString,decodeQueryString:i.decodeQueryString,getParams:i.getParams,removeEventListener:o.removeEventListener,addEventListener:o.addEventListener,bind:r.bind,isFunction:r.isFunction}},{"./lib/dom":15,"./lib/events":16,"./lib/fn":17,"./lib/url":18}],20:[function(t,e){"use strict";function n(t,e){var n=window.getComputedStyle?getComputedStyle(t):t.currentStyle;return n[e]}function i(){return{html:{height:o.style.height||"",overflow:n(o,"overflow"),position:n(o,"position")},body:{height:s.style.height||"",overflow:n(s,"overflow")}}}function r(t,e){this.assetsUrl=t,this.container=e||document.body,this.iframe=null,o=document.documentElement,s=document.body,this.merchantPageDefaultStyles=i()}var o,s,a=t("braintree-utilities"),u=t("../shared/receiver"),c="1.2.0";r.prototype.get=function(t,e){var n=this,i=this.constructAuthorizationURL(t);this.container&&a.isFunction(this.container)?this.container(i+"&no_style=1"):this.insertIframe(i),new u(function(t){a.isFunction(n.container)||n.removeIframe(),e(t)})},r.prototype.removeIframe=function(){this.container&&this.container.nodeType&&1===this.container.nodeType?this.container.removeChild(this.iframe):this.container&&window.jQuery&&this.container instanceof jQuery?$(this.iframe,this.container).remove():"string"==typeof this.container&&document.getElementById(this.container).removeChild(this.iframe),this.unlockMerchantWindowSize()},r.prototype.insertIframe=function(t){var e=document.createElement("iframe");if(e.src=t,this.applyStyles(e),this.lockMerchantWindowSize(),this.container&&this.container.nodeType&&1===this.container.nodeType)this.container.appendChild(e);else if(this.container&&window.jQuery&&this.container instanceof jQuery&&0!==this.container.length)this.container.append(e);else{if("string"!=typeof this.container||!document.getElementById(this.container))throw new Error("Unable to find valid container for iframe.");document.getElementById(this.container).appendChild(e)}this.iframe=e},r.prototype.applyStyles=function(t){t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.height="100%",t.style.width="100%",t.setAttribute("frameborder","0"),t.setAttribute("allowTransparency","true"),t.style.border="0",t.style.zIndex="99999"},r.prototype.lockMerchantWindowSize=function(){o.style.overflow="hidden",s.style.overflow="hidden",s.style.height="100%"},r.prototype.unlockMerchantWindowSize=function(){var t=this.merchantPageDefaultStyles;s.style.height=t.body.height,s.style.overflow=t.body.overflow,o.style.overflow=t.html.overflow},r.prototype.constructAuthorizationURL=function(t){var e,n=window.location.href;return n.indexOf("#")>-1&&(n=n.split("#")[0]),e=a.makeQueryString({acsUrl:t.acsUrl,pareq:t.pareq,termUrl:t.termUrl+"&three_d_secure_version="+c,md:t.md,parentUrl:n}),this.assetsUrl+"/3ds/"+c+"/html/style_frame?"+e},e.exports=r},{"../shared/receiver":24,"braintree-utilities":19}],21:[function(t,e){"use strict";function n(){}function i(t,e){e=e||{},this.clientToken=e.clientToken,this.container=e.container,this.api=t,this.nonce=null,this._boundHandleUserClose=r.bind(this._handleUserClose,this)}var r=t("braintree-utilities"),o=t("./authorization_service");i.prototype.verify=function(t,e){if(!r.isFunction(e))throw this.api.sendAnalyticsEvents("3ds.web.no_callback"),new Error("No suitable callback argument was given");r.isFunction(t.onUserClose)&&(this._onUserClose=t.onUserClose);var n={nonce:"",amount:t.amount},i=t.creditCard;if("string"==typeof i)n.nonce=i,this.api.sendAnalyticsEvents("3ds.web.verify.nonce"),this.startVerification(n,e);else{var o=this,s=function(t,i){return t?e(t):(n.nonce=i,void o.startVerification(n,e))};this.api.sendAnalyticsEvents("3ds.web.verify.credit_card"),this.api.tokenizeCard(i,s)}},i.prototype.startVerification=function(t,e){this.api.lookup3DS(t,r.bind(this.handleLookupResponse(e),this))},i.prototype.handleLookupResponse=function(t){var e=this;return function(n,i){var s;n?t(n.error):i.lookup&&i.lookup.acsUrl&&i.lookup.acsUrl.length>0?(e.nonce=i.paymentMethod.nonce,s=new o(this.clientToken.assetsUrl,this.container),s.get(i.lookup,r.bind(this.handleAuthenticationResponse(t),this)),this._detachListeners(),this._attachListeners()):(e.nonce=i.paymentMethod.nonce,t(null,{nonce:e.nonce,verificationDetails:i.threeDSecureInfo}))}},i.prototype.handleAuthenticationResponse=function(t){return function(e){var n,i=r.decodeQueryString(e);i.user_closed||(n=JSON.parse(i.auth_response),n.success?t(null,{nonce:n.paymentMethod.nonce,verificationDetails:n.threeDSecureInfo}):n.threeDSecureInfo&&n.threeDSecureInfo.liabilityShiftPossible?t(null,{nonce:this.nonce,verificationDetails:n.threeDSecureInfo}):t(n.error))}},i.prototype._attachListeners=function(){r.addEventListener(window,"message",this._boundHandleUserClose)},i.prototype._detachListeners=function(){r.removeEventListener(window,"message",this._boundHandleUserClose)},i.prototype._handleUserClose=function(t){"user_closed=true"===t.data&&this._onUserClose()},i.prototype._onUserClose=n,e.exports=i},{"./authorization_service":20,"braintree-utilities":19}],22:[function(t,e){"use strict";var n=t("./client");t("./vendor/json2"),e.exports={create:function(t,e){var i=new n(t,e);return i}}},{"./client":21,"./vendor/json2":23}],23:[function(require,module,exports){"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function quote(t){return escapable.lastIndex=0,escapable.test(t)?'"'+t.replace(escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var n,i,r,o,s,a=gap,u=e[t];switch(u&&"object"==typeof u&&"function"==typeof u.toJSON&&(u=u.toJSON(t)),"function"==typeof rep&&(u=rep.call(e,t,u)),typeof u){case"string":return quote(u);case"number":return isFinite(u)?String(u):"null";case"boolean":case"null":return String(u);case"object":if(!u)return"null";if(gap+=indent,s=[],"[object Array]"===Object.prototype.toString.apply(u)){for(o=u.length,n=0;o>n;n+=1)s[n]=str(n,u)||"null";return r=0===s.length?"[]":gap?"[\n"+gap+s.join(",\n"+gap)+"\n"+a+"]":"["+s.join(",")+"]",gap=a,r}if(rep&&"object"==typeof rep)for(o=rep.length,n=0;o>n;n+=1)"string"==typeof rep[n]&&(i=rep[n],r=str(i,u),r&&s.push(quote(i)+(gap?": ":":")+r));else for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(r=str(i,u),r&&s.push(quote(i)+(gap?": ":":")+r));return r=0===s.length?"{}":gap?"{\n"+gap+s.join(",\n"+gap)+"\n"+a+"}":"{"+s.join(",")+"}",gap=a,r}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;"function"!=typeof JSON.stringify&&(JSON.stringify=function(t,e,n){var i;if(gap="",indent="","number"==typeof n)for(i=0;n>i;i+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var n,i,r=t[e];if(r&&"object"==typeof r)for(n in r)Object.prototype.hasOwnProperty.call(r,n)&&(i=walk(r,n),void 0!==i?r[n]=i:delete r[n]);return reviver.call(t,e,r)}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}()},{}],24:[function(t,e){"use strict";function n(t){this.postMessageReceiver(t),this.hashChangeReceiver(t)}var i=t("braintree-utilities");n.prototype.postMessageReceiver=function(t){var e=this;this.wrappedCallback=function(n){var i=n.data;(/^(auth_response=)/.test(i)||"user_closed=true"===i)&&(t(i),e.stopListening())},i.addEventListener(window,"message",this.wrappedCallback)},n.prototype.hashChangeReceiver=function(t){var e,n=window.location.hash,i=this;this.poll=setInterval(function(){e=window.location.hash,e.length>0&&e!==n&&(i.stopListening(),e=e.substring(1,e.length),t(e),window.location.hash=n.length>0?n:"")},10)},n.prototype.stopListening=function(){clearTimeout(this.poll),i.removeEventListener(window,"message",this.wrappedCallback)},e.exports=n},{"braintree-utilities":19}],25:[function(t,e){"use strict";function n(t){this.host=t||window,this.handlers=[],i.addEventListener(this.host,"message",i.bind(this.receive,this))}var i=t("braintree-utilities");n.prototype.receive=function(t){var e,i,r,o;try{r=JSON.parse(t.data)}catch(s){return}for(o=r.type,i=new n.Message(this,t.source,r.data),e=0;e<this.handlers.length;e++)this.handlers[e].type===o&&this.handlers[e].handler(i)},n.prototype.send=function(t,e,n){t.postMessage(JSON.stringify({type:e,data:n}),"*")},n.prototype.register=function(t,e){this.handlers.push({type:t,handler:e})},n.prototype.unregister=function(t,e){for(var n=this.handlers.length-1;n>=0;n--)if(this.handlers[n].type===t&&this.handlers[n].handler===e)return this.handlers.splice(n,1)},n.Message=function(t,e,n){this.bus=t,this.source=e,this.content=n},n.Message.prototype.reply=function(t,e){this.bus.send(this.source,t,e)},e.exports=n},{"braintree-utilities":35}],26:[function(t,e){"use strict";function n(t,e){this.bus=t,this.target=e,this.handlers=[],this.bus.register("publish",i.bind(this._handleMessage,this))}var i=t("braintree-utilities");n.prototype._handleMessage=function(t){var e,n=t.content,i=this.handlers[n.channel];if("undefined"!=typeof i)for(e=0;e<i.length;e++)i[e](n.data)},n.prototype.publish=function(t,e){this.bus.send(this.target,"publish",{channel:t,data:e})},n.prototype.subscribe=function(t,e){this.handlers[t]=this.handlers[t]||[],this.handlers[t].push(e)},n.prototype.unsubscribe=function(t,e){var n,i=this.handlers[t];if("undefined"!=typeof i)for(n=0;n<i.length;n++)i[n]===e&&i.splice(n,1)},e.exports=n},{"braintree-utilities":35}],27:[function(t,e){"use strict";function n(t){this.bus=t,this.frames=[],this.handlers=[]}n.prototype.subscribe=function(t,e){this.handlers[t]=this.handlers[t]||[],this.handlers[t].push(e)},n.prototype.registerFrame=function(t){this.frames.push(t)},n.prototype.unregisterFrame=function(t){for(var e=0;e<this.frames.length;e++)this.frames[e]===t&&this.frames.splice(e,1)},n.prototype.publish=function(t,e){var n,i=this.handlers[t];if("undefined"!=typeof i)for(n=0;n<i.length;n++)i[n](e);for(n=0;n<this.frames.length;n++)this.bus.send(this.frames[n],"publish",{channel:t,data:e})},n.prototype.unsubscribe=function(t,e){var n,i=this.handlers[t];if("undefined"!=typeof i)for(n=0;n<i.length;n++)i[n]===e&&i.splice(n,1)},e.exports=n},{}],28:[function(t,e){"use strict";function n(t,e){this.bus=t,this.target=e||window.parent,this.counter=0,this.callbacks={},this.bus.register("rpc_response",i.bind(this._handleResponse,this))}var i=t("braintree-utilities");n.prototype._handleResponse=function(t){var e=t.content,n=this.callbacks[e.id];"function"==typeof n&&(n.apply(null,e.response),delete this.callbacks[e.id])},n.prototype.invoke=function(t,e,n){var i=this.counter++;this.callbacks[i]=n,this.bus.send(this.target,"rpc_request",{id:i,method:t,args:e})},e.exports=n},{"braintree-utilities":35}],29:[function(t,e){"use strict";function n(t){this.bus=t,this.methods={},this.bus.register("rpc_request",i.bind(this._handleRequest,this))}var i=t("braintree-utilities");n.prototype._handleRequest=function(t){var e,n=t.content,i=n.args||[],r=this.methods[n.method];"function"==typeof r&&(e=function(){t.reply("rpc_response",{id:n.id,response:Array.prototype.slice.call(arguments)})},i.push(e),r.apply(null,i))},n.prototype.define=function(t,e){this.methods[t]=e},e.exports=n},{"braintree-utilities":35}],30:[function(t,e){var n=t("./lib/message-bus"),i=t("./lib/pubsub-client"),r=t("./lib/pubsub-server"),o=t("./lib/rpc-client"),s=t("./lib/rpc-server");e.exports={MessageBus:n,PubsubClient:i,PubsubServer:r,RPCClient:o,RPCServer:s}},{"./lib/message-bus":25,"./lib/pubsub-client":26,"./lib/pubsub-server":27,"./lib/rpc-client":28,"./lib/rpc-server":29}],31:[function(t,e){"use strict";function n(t,e){if(e=e||"["+t+"] is not a valid DOM Element",t&&t.nodeType&&1===t.nodeType)return t;if(t&&window.jQuery&&t instanceof jQuery&&0!==t.length)return t[0];if("string"==typeof t&&document.getElementById(t))return document.getElementById(t);throw new Error(e)}e.exports={normalizeElement:n}},{}],32:[function(t,e){"use strict";function n(t,e,n){t.addEventListener?t.addEventListener(e,n,!1):t.attachEvent&&t.attachEvent("on"+e,n)}function i(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent&&t.detachEvent("on"+e,n)}e.exports={removeEventListener:i,addEventListener:n}},{}],33:[function(t,e){"use strict";function n(t){return"[object Function]"===Object.prototype.toString.call(t)}function i(t,e){return function(){t.apply(e,arguments)}}e.exports={bind:i,isFunction:n}},{}],34:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],35:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":31,"./lib/events":32,"./lib/fn":33,"./lib/url":34,dup:19}],36:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],37:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],38:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],39:[function(t,e){"use strict";function n(t){var e,n,i,r,o=[{min:0,max:180,chars:7},{min:181,max:620,chars:14},{min:621,max:960,chars:22}];for(r=o.length,t=t||window.innerWidth,n=0;r>n;n++)i=o[n],t>=i.min&&t<=i.max&&(e=i.chars);return e||60}function i(t,e){var n,i;return-1===t.indexOf("@")?t:(t=t.split("@"),n=t[0],i=t[1],n.length>e&&(n=n.slice(0,e)+"..."),i.length>e&&(i="..."+i.slice(-e)),n+"@"+i)}e.exports={truncateEmail:i,getMaxCharLength:n}},{}],40:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],41:[function(t,e){var n=t("./lib/dom"),i=t("./lib/url"),r=t("./lib/fn"),o=t("./lib/events"),s=t("./lib/string");e.exports={string:s,normalizeElement:n.normalizeElement,isBrowserHttps:i.isBrowserHttps,makeQueryString:i.makeQueryString,decodeQueryString:i.decodeQueryString,getParams:i.getParams,removeEventListener:o.removeEventListener,addEventListener:o.addEventListener,bind:r.bind,isFunction:r.isFunction}},{"./lib/dom":36,"./lib/events":37,"./lib/fn":38,"./lib/string":39,"./lib/url":40}],42:[function(t,e){"use strict";var n=t("framebus");n.events=t("./lib/events"),e.exports=n},{"./lib/events":43,framebus:44}],43:[function(t,e){"use strict";for(var n=["PAYMENT_METHOD_REQUEST","PAYMENT_METHOD_RECEIVED","PAYMENT_METHOD_GENERATED","PAYMENT_METHOD_CANCELLED","PAYMENT_METHOD_ERROR","CONFIGURATION_REQUEST","ERROR","WARNING"],i={},r=0;r<n.length;r++){var o=n[r];i[o]=o}e.exports=i},{}],44:[function(t,e,n){"use strict";!function(t,i){"function"==typeof define&&define.amd?define([],i):"object"==typeof n?e.exports=i():t.framebus=i()}(this,function(){function t(t,e,n){var r;return n=n||"*","string"!=typeof t?!1:"string"!=typeof n?!1:(r=i(t,e,n),c(h.top,r,n),!0)}function e(t,e,n){return n=n||"*",p(t,e,n)?!1:(d[n]=d[n]||{},d[n][t]=d[n][t]||[],d[n][t].push(e),!0)}function n(t,e,n){var i,r;if(n=n||"*",p(t,e,n))return!1;if(r=d[n]&&d[n][t],!r)return!1;for(i=0;i<r.length;i++)if(r[i]===e)return r.splice(i,1),!0;return!1}function i(t,e,n){var i={event:t};return"function"==typeof e?i.reply=l(e,n):i.data=e,JSON.stringify(i)}function r(t){var e;try{e=JSON.parse(t.data)}catch(n){return!1}return null==e.event?!1:(null!=e.reply&&(e.data=function(n){var r=i(e.reply,n,t.origin);t.source.postMessage(r,t.origin)}),e)}function o(t){h||(h=t,h.addEventListener?h.addEventListener("message",a,!1):h.attachEvent?h.attachEvent("onmessage",a):null===h.onmessage?h.onmessage=a:h=null)}function s(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=16*Math.random()|0,n="x"===t?e:3&e|8;return n.toString(16)})}function a(t){var e;"string"==typeof t.data&&(e=r(t),e&&(u("*",e.event,e.data,t.origin),u(t.origin,e.event,e.data,t.origin)))}function u(t,e,n,i){var r;if(d[t]&&d[t][e])for(r=0;r<d[t][e].length;r++)d[t][e][r](n,i)}function c(t,e,n){var i;for(t.postMessage(e,n),i=0;i<t.frames.length;i++)c(t.frames[i],e,n)}function l(t,i){function r(e,s){t(e,s),n(o,r,i)}var o=s();return e(o,r,i),o}function p(t,e,n){return"string"!=typeof t?!0:"function"!=typeof e?!0:"string"!=typeof n?!0:!1}var h,d={};return o(window),{publish:t,pub:t,trigger:t,emit:t,subscribe:e,sub:e,on:e,unsubscribe:n,unsub:n,off:n}})},{}],45:[function(t,e){"use strict";function n(t,e){u.emit(u.events.ERROR,{type:e,message:t})}function i(){var t=a.isIE();return t&&8===t.version}function r(t){if(null==t.apiClient)return n("settings.apiClient is required for coinbase",c),!1;if(!t.configuration.coinbaseEnabled)return n("Coinbase is not enabled for your merchant account",c),!1;var e=t.coinbase;return e&&(e.container||e.button)?e.container&&e.button?(n("options.coinbase.container and options.coinbase.button are mutually exclusive",c),!1):(i()&&n("Coinbase is not supported by your browser. Please consider upgrading","UNSUPPORTED_BROWSER"),!0):(n("Either options.coinbase.container or options.coinbase.button is required for coinbase integrations",c),!1)}function o(t){return r(t)?new s(t):void 0}var s=t("./lib/coinbase"),a=t("./lib/browser"),u=t("braintree-bus"),c="CONFIGURATION";e.exports={create:o}},{"./lib/browser":46,"./lib/coinbase":48,"braintree-bus":56}],46:[function(t,e){(function(t){"use strict";function n(){var t=null,e="";try{new ActiveXObject("")}catch(n){e=n.name}try{t=!!new ActiveXObject("htmlfile")}catch(n){t=!1}return t="ReferenceError"!==e&&t===!1?!1:!0,!t}function i(){var e={version:null};return/Trident/.test(t.navigator.userAgent)&&(e.version=11),/MSIE 10/.test(t.navigator.userAgent)&&(e.version=10),/MSIE 9/.test(t.navigator.userAgent)&&(e.version=9),/MSIE 8/.test(t.navigator.userAgent)&&(e.version=8),e
3
+ }function r(){return/MSIE|Trident/.test(t.navigator.userAgent)?i():null}e.exports={isMetroBrowser:n,isIE:r}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],47:[function(t,e){"use strict";function n(t,e,n){return t?(i.emit(i.events.ERROR,t.error),void n.sendAnalyticsEvents("coinbase.web.error")):(i.emit(i.events.PAYMENT_METHOD_GENERATED,e),void n.sendAnalyticsEvents("coinbase.web.success"))}var i=t("braintree-bus");e.exports={tokenize:n}},{"braintree-bus":56}],48:[function(t,e){(function(n){"use strict";function i(){}function r(t){return{clientId:t.configuration.coinbase.clientId,redirectUrl:t.configuration.coinbase.redirectUrl,scopes:t.configuration.coinbase.scopes||l.SCOPES,meta:{authorizations_merchant_account:t.configuration.coinbase.merchantAccount||""}}}function o(t){var e;this.buttonId=t.coinbase.button||l.BUTTON_ID,this.apiClient=t.apiClient,this.assetsUrl=t.configuration.assetsUrl,this._onOAuthSuccess=s.bind(this._onOAuthSuccess,this),this._handleButtonClick=s.bind(this._handleButtonClick,this),this.popupParams=r(t),this.redirectDoneInterval=null,e=document.body,n.braintreeCoinbaseRedirectCallback=this._onOAuthSuccess,t.coinbase.container?(e=s.normalizeElement(t.coinbase.container),this._insertFrame(e)):s.addEventListener(e,"click",this._handleButtonClick),this._sendAnalyticsEvents("coinbase.web.initialized")}var s=t("braintree-utilities"),a=t("./dom/composer"),u=t("./url-composer"),c=t("./callbacks"),l=t("./constants"),p=t("braintree-bus"),h=t("./detector");o.prototype._sendAnalyticsEvents=function(t){this.apiClient.sendAnalyticsEvents(t)},o.prototype._insertFrame=function(t){var e=a.createFrame({src:this.assetsUrl+"/coinbase/"+l.VERSION+"/coinbase-frame.html"});t.appendChild(e)},o.prototype._onOAuthSuccess=function(t){t.code&&(p.emit("coinbase:view:navigate","loading"),this._clearPollForRedirectDone(),this.apiClient.tokenizeCoinbase({code:t.code,query:u.getQueryString()},s.bind(function(t,e){c.tokenize.apply(null,[t,e,this.apiClient])},this)))},o.prototype._clearPollForRedirectDone=function(){this.redirectDoneInterval&&(clearInterval(this.redirectDoneInterval),this.redirectDoneInterval=null)},o.prototype._pollForRedirectDone=function(t){this.redirectDoneInterval=setInterval(s.bind(function(){var e;if(null==t||t.closed)return void this._clearPollForRedirectDone();try{e=s.decodeQueryString(t.location.search.replace(/^\?/,"")).code}catch(n){return}e&&(this._onOAuthSuccess({code:e}),t.close())},this),100)},o.prototype._openPopup=function(){var t;this._sendAnalyticsEvents("coinbase.web.start.popup"),t=a.createPopup(u.compose(this.popupParams)),n.popup=t,t.focus(),h.shouldPoll()&&(this._pollForRedirectDone(t),n.braintreeCoinbaseRedirectCallback=i)},o.prototype._handleButtonClick=function(t){for(var e=t.target||t.srcElement;;){if(null==e)return;if(e===t.currentTarget)return;if(e.id===this.buttonId)break;e=e.parentNode}t&&t.preventDefault?t.preventDefault():t.returnValue=!1,this._openPopup()},e.exports=o}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./callbacks":47,"./constants":49,"./detector":50,"./dom/composer":52,"./url-composer":55,"braintree-bus":56,"braintree-utilities":64}],49:[function(t,e){"use strict";e.exports={BASE_URL:"https://coinbase.com",ORIGIN_URL:"https://www.coinbase.com",FRAME_NAME:"braintree-coinbase-frame",POPUP_NAME:"coinbase",BUTTON_ID:"bt-coinbase-button",SCOPES:"send",VERSION:"0.0.3"}},{}],50:[function(t,e){"use strict";function n(){var t=r.isIE();return t&&t.version>9}function i(){return r.isIE()&&r.isMetroBrowser()}var r=t("./browser");e.exports={shouldPoll:n,shouldCloseFromParent:i}},{"./browser":46}],51:[function(t,e){"use strict";function n(t){var e=document.createElement("button");return t=t||{},e.id=t.id||"coinbase-button",e.style.backgroundColor=t.backgroundColor||"#EEE",e.style.color=t.color||"#4597C3",e.style.border=t.border||"0",e.style.borderRadius=t.borderRadius||"6px",e.style.padding=t.padding||"12px",e.innerHTML=t.innerHTML||"coinbase",e}e.exports={create:n}},{}],52:[function(t,e){"use strict";var n=t("./popup"),i=t("./button"),r=t("./frame");e.exports={createButton:i.create,createPopup:n.create,createFrame:r.create}},{"./button":51,"./frame":53,"./popup":54}],53:[function(t,e){"use strict";function n(t){var e=document.createElement("iframe");return e.src=t.src,e.id=i.FRAME_NAME,e.name=i.FRAME_NAME,e.allowTransparency=!0,e.height="70px",e.width="100%",e.frameBorder=0,e.style.padding=0,e.style.margin=0,e.style.border=0,e.style.outline="none",e}var i=t("../constants");e.exports={create:n}},{"../constants":49}],54:[function(t,e){(function(n){"use strict";function i(t){var e=[];for(var n in t)t.hasOwnProperty(n)&&e.push([n,t[n]].join("="));return e.join(",")}function r(){var t=850,e=600;return i({width:t,height:e,left:(screen.width-t)/2,top:(screen.height-e)/4})}function o(t){return n.open(t,s.POPUP_NAME,r())}var s=t("../constants");e.exports={create:o}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../constants":49}],55:[function(t,e){"use strict";function n(){return"version="+r.VERSION}function i(t){var e=r.BASE_URL+"/oauth/authorize?response_type=code",i=t.redirectUrl+"?"+n();if(e+="&redirect_uri="+encodeURIComponent(i),e+="&client_id="+t.clientId,t.scopes&&(e+="&scope="+encodeURIComponent(t.scopes)),t.meta)for(var o in t.meta)t.meta.hasOwnProperty(o)&&(e+="&meta["+encodeURIComponent(o)+"]="+encodeURIComponent(t.meta[o]));return e}var r=t("./constants");e.exports={compose:i,getQueryString:n}},{"./constants":49}],56:[function(t,e,n){arguments[4][42][0].apply(n,arguments)},{"./lib/events":57,dup:42,framebus:58}],57:[function(t,e,n){arguments[4][43][0].apply(n,arguments)},{dup:43}],58:[function(t,e,n){arguments[4][44][0].apply(n,arguments)},{dup:44}],59:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],60:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],61:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],62:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],63:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],64:[function(t,e,n){arguments[4][41][0].apply(n,arguments)},{"./lib/dom":59,"./lib/events":60,"./lib/fn":61,"./lib/string":62,"./lib/url":63,dup:41}],65:[function(t,e){(function(n){"use strict";function i(t,e){return t.status>=400?[t,null]:[null,e(t)]}function r(t){var e;this.attrs={},t.hasOwnProperty("sharedCustomerIdentifier")&&(this.attrs.sharedCustomerIdentifier=t.sharedCustomerIdentifier),e=c(t.clientToken),this.driver=t.driver||l,this.authUrl=e.authUrl,this.analyticsUrl=e.analytics?e.analytics.url:void 0,this.clientApiUrl=e.clientApiUrl,this.customerId=t.customerId,this.challenges=e.challenges,this.integration=t.integration||"";var n=u.create(this,{container:t.container,clientToken:e});this.verify3DS=a.bind(n.verify,n),this.attrs.authorizationFingerprint=e.authorizationFingerprint,this.attrs.sharedCustomerIdentifierType=t.sharedCustomerIdentifierType,e.merchantAccountId&&(this.attrs.merchantAccountId=e.merchantAccountId),this.timeoutWatchers=[],this.requestTimeout=t.hasOwnProperty("timeout")?t.timeout:6e4}function o(){}function s(t,e){var n,i={};for(n in t)t.hasOwnProperty(n)&&(i[n]=t[n]);for(n in e)e.hasOwnProperty(n)&&(i[n]=e[n]);return i}var a=t("braintree-utilities"),u=t("braintree-3ds"),c=t("./parse-client-token"),l=t("./jsonp-driver"),p=t("./util"),h=t("./sepa-mandate"),d=t("./sepa-bank-account"),f=t("./credit-card"),m=t("./coinbase-account"),y=t("./root-data"),g=t("./normalize-api-fields").normalizeCreditCardFields;r.prototype.requestWithTimeout=function(t,e,n,r,s){s=s||o;var a,u,c=this;y.get(function(o){u="braintree/web/"+o.sdkVersion,e.braintreeLibraryVersion=u,e.hasOwnProperty("analytics")&&e.hasOwnProperty("_meta")&&(e._meta.sdkVersion=u,e._meta.merchantAppId=o.merchantAppId),a=r(t,e,function(t,e){if(c.timeoutWatchers[e]){clearTimeout(c.timeoutWatchers[e]);var r=i(t,function(t){return n(t)});s.apply(null,r)}}),c.requestTimeout>0?this.timeoutWatchers[a]=setTimeout(function(){c.timeoutWatchers[a]=null,s.apply(null,[{errors:"Unknown error"},null])},c.requestTimeout):s.apply(null,[{errors:"Unknown error"},null])},this)},r.prototype.post=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.post,i)},r.prototype.get=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.get,i)},r.prototype.put=function(t,e,n,i){this.requestWithTimeout(t,e,n,this.driver.put,i)},r.prototype.getCreditCards=function(t){this.get(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods"]),this.attrs,function(t){var e=0,n=t.paymentMethods.length,i=[];for(e;n>e;e++)i.push(new f(t.paymentMethods[e]));return i},t)},r.prototype.tokenizeCoinbase=function(t,e){t.options={validate:!1},this.addCoinbase(t,function(t,n){t?e(t,null):n&&n.nonce?e(t,n):e("Unable to tokenize coinbase account.",null)})},r.prototype.tokenizeCard=function(t,e){t.options={validate:!1},this.addCreditCard(t,function(t,n){n&&n.nonce?e(t,n.nonce,{type:n.type}):e("Unable to tokenize card.",null)})},r.prototype.lookup3DS=function(t,e){var n=p.joinUrlFragments([this.clientApiUrl,"v1/payment_methods",t.nonce,"three_d_secure/lookup"]),i=s(this.attrs,{amount:t.amount});this.post(n,i,function(t){return t},e)},r.prototype.addSEPAMandate=function(t,e){var n=s(this.attrs,{sepaMandate:t});this.post(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates.json"]),n,function(t){return new h(t.sepaMandates[0])},e)},r.prototype.acceptSEPAMandate=function(t,e){this.put(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates",t,"accept"]),this.attrs,function(t){return new d(t.sepaBankAccounts[0])},e)},r.prototype.getSEPAMandate=function(t,e){var n;n=t.paymentMethodToken?s(this.attrs,{paymentMethodToken:t.paymentMethodToken}):this.attrs,this.get(p.joinUrlFragments([this.clientApiUrl,"v1","sepa_mandates",t.mandateReferenceNumber||""]),n,function(t){return new h(t.sepaMandates[0])},e)},r.prototype.addCoinbase=function(t,e){var n;delete t.share,n=s(this.attrs,{coinbaseAccount:t,_meta:{integration:this.integration||"custom",source:"coinbase"}}),this.post(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/coinbase_accounts"]),n,function(t){return new m(t.coinbaseAccounts[0])},e)},r.prototype.addCreditCard=function(t,e){var n,i=t.share;delete t.share;var r=g(t);n=s(this.attrs,{share:i,creditCard:r,_meta:{integration:this.integration||"custom",source:"form"}}),this.post(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/credit_cards"]),n,function(t){return new f(t.creditCards[0])},e)},r.prototype.unlockCreditCard=function(t,e,n){var i=s(this.attrs,{challengeResponses:e});this.put(p.joinUrlFragments([this.clientApiUrl,"v1","payment_methods/",t.nonce]),i,function(t){return new f(t.paymentMethods[0])},n)},r.prototype.sendAnalyticsEvents=function(t,e){var i,r=this.analyticsUrl,o=[];if(t=p.isArray(t)?t:[t],!r)return void(e&&e.apply(null,[null,{}]));for(var a in t)t.hasOwnProperty(a)&&o.push({kind:t[a]});i=s(this.attrs,{analytics:o,_meta:{platform:"web",platformVersion:n.navigator.userAgent,integrationType:this.integration}}),this.post(r,i,function(t){return t},e)},e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./coinbase-account":66,"./credit-card":67,"./jsonp-driver":68,"./normalize-api-fields":70,"./parse-client-token":71,"./root-data":73,"./sepa-bank-account":74,"./sepa-mandate":75,"./util":76,"braintree-3ds":85,"braintree-utilities":104}],66:[function(t,e,n){arguments[4][3][0].apply(n,arguments)},{dup:3}],67:[function(t,e,n){arguments[4][4][0].apply(n,arguments)},{dup:4}],68:[function(t,e,n){arguments[4][5][0].apply(n,arguments)},{"./jsonp":69,dup:5}],69:[function(t,e,n){arguments[4][6][0].apply(n,arguments)},{"./util":76,dup:6}],70:[function(t,e,n){arguments[4][7][0].apply(n,arguments)},{dup:7}],71:[function(t,e,n){arguments[4][8][0].apply(n,arguments)},{"./polyfill":72,dup:8}],72:[function(t,e,n){arguments[4][9][0].apply(n,arguments)},{dup:9}],73:[function(t,e,n){arguments[4][10][0].apply(n,arguments)},{"braintree-rpc":93,dup:10}],74:[function(t,e,n){arguments[4][11][0].apply(n,arguments)},{dup:11}],75:[function(t,e,n){arguments[4][12][0].apply(n,arguments)},{dup:12}],76:[function(t,e,n){arguments[4][13][0].apply(n,arguments)},{dup:13}],77:[function(t,e,n){arguments[4][14][0].apply(n,arguments)},{"./lib/client":65,"./lib/jsonp":69,"./lib/jsonp-driver":68,"./lib/parse-client-token":71,"./lib/util":76,dup:14}],78:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],79:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],80:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],81:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],82:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":78,"./lib/events":79,"./lib/fn":80,"./lib/url":81,dup:19}],83:[function(t,e){"use strict";function n(t,e){var n=window.getComputedStyle?getComputedStyle(t):t.currentStyle;return n[e]}function i(){return{html:{height:o.style.height||"",overflow:n(o,"overflow"),position:n(o,"position")},body:{height:s.style.height||"",overflow:n(s,"overflow")}}}function r(t,e){this.assetsUrl=t,this.container=e||document.body,this.iframe=null,o=document.documentElement,s=document.body,this.merchantPageDefaultStyles=i()}var o,s,a=t("braintree-utilities"),u=t("../shared/receiver"),c="1.1.0";r.prototype.get=function(t,e){var n=this,i=this.constructAuthorizationURL(t);this.container&&a.isFunction(this.container)?this.container(i+"&no_style=1"):this.insertIframe(i),new u(function(t){a.isFunction(n.container)||n.removeIframe(),e(t)})},r.prototype.removeIframe=function(){this.container&&this.container.nodeType&&1===this.container.nodeType?this.container.removeChild(this.iframe):this.container&&window.jQuery&&this.container instanceof jQuery?$(this.iframe,this.container).remove():"string"==typeof this.container&&document.getElementById(this.container).removeChild(this.iframe),this.unlockMerchantWindowSize()},r.prototype.insertIframe=function(t){var e=document.createElement("iframe");if(e.src=t,this.applyStyles(e),this.lockMerchantWindowSize(),this.container&&this.container.nodeType&&1===this.container.nodeType)this.container.appendChild(e);else if(this.container&&window.jQuery&&this.container instanceof jQuery&&0!==this.container.length)this.container.append(e);else{if("string"!=typeof this.container||!document.getElementById(this.container))throw new Error("Unable to find valid container for iframe.");document.getElementById(this.container).appendChild(e)}this.iframe=e},r.prototype.applyStyles=function(t){t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.height="100%",t.style.width="100%",t.setAttribute("frameborder","0"),t.setAttribute("allowTransparency","true"),t.style.border="0",t.style.zIndex="99999"},r.prototype.lockMerchantWindowSize=function(){o.style.overflow="hidden",s.style.overflow="hidden",s.style.height="100%"},r.prototype.unlockMerchantWindowSize=function(){var t=this.merchantPageDefaultStyles;s.style.height=t.body.height,s.style.overflow=t.body.overflow,o.style.overflow=t.html.overflow},r.prototype.constructAuthorizationURL=function(t){var e,n=window.location.href;return n.indexOf("#")>-1&&(n=n.split("#")[0]),e=a.makeQueryString({acsUrl:t.acsUrl,pareq:t.pareq,termUrl:t.termUrl+"&three_d_secure_version="+c,md:t.md,parentUrl:n}),this.assetsUrl+"/3ds/"+c+"/html/style_frame?"+e},e.exports=r},{"../shared/receiver":87,"braintree-utilities":82}],84:[function(t,e){"use strict";function n(t,e){e=e||{},this.clientToken=e.clientToken,this.container=e.container,this.api=t,this.nonce=null}var i=t("braintree-utilities"),r=t("./authorization_service");n.prototype.verify=function(t,e){if(!i.isFunction(e))throw this.api.sendAnalyticsEvents("3ds.web.no_callback"),new Error("No suitable callback argument was given");var n={nonce:"",amount:t.amount},r=t.creditCard;if("string"==typeof r)n.nonce=r,this.api.sendAnalyticsEvents("3ds.web.verify.nonce"),this.startVerification(n,e);else{var o=this,s=function(t,i){return t?e(t):(n.nonce=i,void o.startVerification(n,e))};this.api.sendAnalyticsEvents("3ds.web.verify.credit_card"),this.api.tokenizeCard(r,s)}},n.prototype.startVerification=function(t,e){this.api.lookup3DS(t,i.bind(this.handleLookupResponse(e),this))},n.prototype.handleLookupResponse=function(t){var e=this;return function(n,o){var s;n?t(n.error):o.lookup&&o.lookup.acsUrl&&o.lookup.acsUrl.length>0?(e.nonce=o.paymentMethod.nonce,s=new r(this.clientToken.assetsUrl,this.container),s.get(o.lookup,i.bind(this.handleAuthenticationResponse(t),this))):(e.nonce=o.paymentMethod.nonce,t(null,{nonce:e.nonce,verificationDetails:o.threeDSecureInfo}))}},n.prototype.handleAuthenticationResponse=function(t){return function(e){var n,r=i.decodeQueryString(e);r.user_closed||(n=JSON.parse(r.auth_response),n.success?t(null,{nonce:n.paymentMethod.nonce,verificationDetails:n.threeDSecureInfo}):n.threeDSecureInfo&&n.threeDSecureInfo.liabilityShiftPossible?t(null,{nonce:this.nonce,verificationDetails:n.threeDSecureInfo}):t(n.error))}},e.exports=n},{"./authorization_service":83,"braintree-utilities":82}],85:[function(t,e,n){arguments[4][22][0].apply(n,arguments)},{"./client":84,"./vendor/json2":86,dup:22}],86:[function(t,e,n){arguments[4][23][0].apply(n,arguments)},{dup:23}],87:[function(t,e){"use strict";function n(t){this.postMessageReceiver(t),this.hashChangeReceiver(t)}var i=t("braintree-utilities");n.prototype.postMessageReceiver=function(t){var e=this;this.wrappedCallback=function(n){t(n.data),e.stopListening()},i.addEventListener(window,"message",this.wrappedCallback)},n.prototype.hashChangeReceiver=function(t){var e,n=window.location.hash,i=this;this.poll=setInterval(function(){e=window.location.hash,e.length>0&&e!==n&&(i.stopListening(),e=e.substring(1,e.length),t(e),window.location.hash=n.length>0?n:"")},10)},n.prototype.stopListening=function(){clearTimeout(this.poll),i.removeEventListener(window,"message",this.wrappedCallback)},e.exports=n},{"braintree-utilities":82}],88:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":98,dup:25}],89:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":98,dup:26}],90:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],91:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":98,dup:28}],92:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":98,dup:29}],93:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":88,"./lib/pubsub-client":89,"./lib/pubsub-server":90,"./lib/rpc-client":91,"./lib/rpc-server":92,dup:30}],94:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],95:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],96:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],97:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],98:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":94,"./lib/events":95,"./lib/fn":96,"./lib/url":97,dup:19}],99:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],100:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],101:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],102:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],103:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],104:[function(t,e,n){arguments[4][41][0].apply(n,arguments)},{"./lib/dom":99,"./lib/events":100,"./lib/fn":101,"./lib/string":102,"./lib/url":103,dup:41}],105:[function(t,e,n){arguments[4][42][0].apply(n,arguments)},{"./lib/events":106,dup:42,framebus:107}],106:[function(t,e,n){arguments[4][43][0].apply(n,arguments)},{dup:43}],107:[function(t,e,n){arguments[4][44][0].apply(n,arguments)},{dup:44}],108:[function(t,e,n){arguments[4][2][0].apply(n,arguments)},{"./coinbase-account":109,"./credit-card":110,"./jsonp-driver":111,"./normalize-api-fields":113,"./parse-client-token":114,"./root-data":116,"./sepa-bank-account":117,"./sepa-mandate":118,"./util":119,"braintree-3ds":128,"braintree-utilities":147,dup:2}],109:[function(t,e,n){arguments[4][3][0].apply(n,arguments)},{dup:3}],110:[function(t,e,n){arguments[4][4][0].apply(n,arguments)},{dup:4}],111:[function(t,e,n){arguments[4][5][0].apply(n,arguments)},{"./jsonp":112,dup:5}],112:[function(t,e,n){arguments[4][6][0].apply(n,arguments)},{"./util":119,dup:6}],113:[function(t,e,n){arguments[4][7][0].apply(n,arguments)},{dup:7}],114:[function(t,e,n){arguments[4][8][0].apply(n,arguments)},{"./polyfill":115,dup:8}],115:[function(t,e,n){arguments[4][9][0].apply(n,arguments)},{dup:9}],116:[function(t,e,n){arguments[4][10][0].apply(n,arguments)},{"braintree-rpc":136,dup:10}],117:[function(t,e,n){arguments[4][11][0].apply(n,arguments)},{dup:11}],118:[function(t,e,n){arguments[4][12][0].apply(n,arguments)},{dup:12}],119:[function(t,e,n){arguments[4][13][0].apply(n,arguments)},{dup:13}],120:[function(t,e,n){arguments[4][14][0].apply(n,arguments)},{"./lib/client":108,"./lib/jsonp":112,"./lib/jsonp-driver":111,"./lib/parse-client-token":114,"./lib/util":119,dup:14}],121:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],122:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],123:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],124:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],125:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":121,"./lib/events":122,"./lib/fn":123,"./lib/url":124,dup:19}],126:[function(t,e,n){arguments[4][20][0].apply(n,arguments)},{"../shared/receiver":130,"braintree-utilities":125,dup:20}],127:[function(t,e,n){arguments[4][21][0].apply(n,arguments)},{"./authorization_service":126,"braintree-utilities":125,dup:21}],128:[function(t,e,n){arguments[4][22][0].apply(n,arguments)},{"./client":127,"./vendor/json2":129,dup:22}],129:[function(t,e,n){arguments[4][23][0].apply(n,arguments)},{dup:23}],130:[function(t,e,n){arguments[4][24][0].apply(n,arguments)},{"braintree-utilities":125,dup:24}],131:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":141,dup:25}],132:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":141,dup:26}],133:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],134:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":141,dup:28}],135:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":141,dup:29}],136:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":131,"./lib/pubsub-client":132,"./lib/pubsub-server":133,"./lib/rpc-client":134,"./lib/rpc-server":135,dup:30}],137:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],138:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],139:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],140:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],141:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":137,"./lib/events":138,"./lib/fn":139,"./lib/url":140,dup:19}],142:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],143:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],144:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],145:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],146:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],147:[function(t,e,n){arguments[4][41][0].apply(n,arguments)},{"./lib/dom":142,"./lib/events":143,"./lib/fn":144,"./lib/string":145,"./lib/url":146,dup:41}],148:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":158,dup:25}],149:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":158,dup:26}],150:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],151:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":158,dup:28}],152:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":158,dup:29}],153:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":148,"./lib/pubsub-client":149,"./lib/pubsub-server":150,"./lib/rpc-client":151,"./lib/rpc-server":152,dup:30}],154:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],155:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],156:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],157:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],158:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":154,"./lib/events":155,"./lib/fn":156,"./lib/url":157,dup:19}],159:[function(t,e){"use strict";var n,i=Array.prototype.indexOf;n=i?function(t,e){return t.indexOf(e)}:function(t,e){for(var n=0,i=t.length;i>n;n++)if(t[n]===e)return n;return-1},e.exports={indexOf:n}},{}],160:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],161:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],162:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],163:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],164:[function(t,e){"use strict";function n(){return"https:"===window.location.protocol}function i(t){switch(t){case null:case void 0:return"";case!0:return"1";case!1:return"0";default:return encodeURIComponent(t)}}function r(t,e){var n,o,s=[];for(o in t)if(t.hasOwnProperty(o)){var a=t[o];n=e?e+"["+o+"]":o,"object"==typeof a?s.push(r(a,n)):void 0!==a&&null!==a&&s.push(i(n)+"="+i(a))}return s.join("&")}function o(t){for(var e={},n=t.split("&"),i=0;i<n.length;i++){var r=n[i].split("="),o=r[0],s=decodeURIComponent(r[1]);e[o]=s}return e}function s(t){var e=t.split("?");return 2!==e.length?{}:o(e[1])}function a(t){if(t=t.toLowerCase(),!/^http/.test(t))return!1;c.href=t;var e=c.hostname.split("."),n=e.slice(-2).join(".");return-1===u.indexOf(l,n)?!1:!0}var u=t("./array"),c=document.createElement("a"),l=["paypal.com","braintreepayments.com","braintreegateway.com","localhost"];e.exports={isBrowserHttps:n,makeQueryString:r,decodeQueryString:o,getParams:s,isWhitelistedDomain:a}},{"./array":159}],165:[function(t,e){var n=t("./lib/dom"),i=t("./lib/url"),r=t("./lib/fn"),o=t("./lib/events"),s=t("./lib/string"),a=t("./lib/array");e.exports={string:s,array:a,normalizeElement:n.normalizeElement,isBrowserHttps:i.isBrowserHttps,makeQueryString:i.makeQueryString,decodeQueryString:i.decodeQueryString,getParams:i.getParams,isWhitelistedDomain:i.isWhitelistedDomain,removeEventListener:o.removeEventListener,addEventListener:o.addEventListener,bind:r.bind,isFunction:r.isFunction}},{"./lib/array":159,"./lib/dom":160,"./lib/events":161,"./lib/fn":162,"./lib/string":163,"./lib/url":164}],166:[function(t,e){function n(t){var e=window.getComputedStyle?getComputedStyle(t):t.currentStyle;return{overflow:e.overflow||"",height:t.style.height||""}}function i(){return{html:{node:document.documentElement,styles:n(document.documentElement)},body:{node:document.body,styles:n(document.body)}}}function r(t,e){if(!t)throw new Error('Parameter "clientToken" cannot be null');e=e||{},this._clientToken=o.parseClientToken(t),this._clientOptions=e,this.container=e.container,this.merchantPageDefaultStyles=null,this.paymentMethodNonceInputField=e.paymentMethodNonceInputField,this.frame=null,this.popup=null,this.insertFrameFunction=e.insertFrame,this.onSuccess=e.onSuccess,this.onCancelled=e.onCancelled,this.onUnsupported=e.onUnsupported,this.loggedInView=null,this.loggedOutView=null,this.insertUI=!0}var o=t("braintree-api"),s=t("braintree-rpc"),a=t("braintree-utilities"),u=t("./logged-in-view"),c=t("./logged-out-view"),l=t("./overlay-view"),p=t("../shared/util/browser"),h=t("../shared/util/dom"),d=t("../shared/constants"),f=t("../shared/util/util"),m=t("../shared/get-locale");r.prototype.getViewerUrl=function(){var t=this._clientToken.paypal.assetsUrl;return t+"/pwpp/"+d.VERSION+"/html/braintree-frame.html"},r.prototype.getProxyUrl=function(){var t=this._clientToken.paypal.assetsUrl;return t+"/pwpp/"+d.VERSION+"/html/proxy-frame.html"},r.prototype.initialize=function(){if(!this._clientToken.paypalEnabled)return void("function"==typeof this.onUnsupported&&this.onUnsupported(new Error("PayPal is not enabled")));if(!this._isBrowserSecure())return void("function"==typeof this.onUnsupported&&this.onUnsupported(new Error("unsupported protocol detected")));if(this._isAriesCapable()){if(!this._isAriesSupportedCurrency())return void("function"==typeof this.onUnsupported&&this.onUnsupported(new Error("This PayPal integration does not support this currency")));if(!this._isAriesSupportedCountries())return void("function"==typeof this.onUnsupported&&this.onUnsupported(new Error("This PayPal integration does not support this locale")))}return this._isMisconfiguredUnvettedMerchant()?void("function"==typeof this.onUnsupported&&this.onUnsupported(new Error("Unvetted merchant client token does not include a payee email"))):(this._overrideClientTokenProperties(),p.isProxyFrameRequired()&&this._insertProxyFrame(),this._setupDomElements(),this._setupPaymentMethodNonceInputField(),this._setupViews(),void this._createRpcServer())},r.prototype._isSupportedOption=function(t,e){for(var n=e.length,i=!1,r=0;n>r;r++)t.toLowerCase()===e[r].toLowerCase()&&(i=!0);return i},r.prototype._isAriesSupportedCurrency=function(){return this._isSupportedOption(this._clientOptions.currency,d.ARIES_SUPPORTED_CURRENCIES)},r.prototype._isAriesSupportedCountries=function(){return this._isSupportedOption(m(this._clientOptions.locale).split("_")[1],d.ARIES_SUPPORTED_COUNTRIES)},r.prototype._isMisconfiguredUnvettedMerchant=function(){return this._clientToken.paypal.unvettedMerchant&&(!this._isAriesCapable()||!this._clientToken.paypal.payeeEmail)},r.prototype._isBrowserSecure=function(){return a.isBrowserHttps()||p.isPopupSupported()||this._clientToken.paypal.allowHttp},r.prototype._overrideClientTokenProperties=function(){this._clientOptions.displayName&&(this._clientToken.paypal.displayName=this._clientOptions.displayName)},r.prototype._setupDomElements=function(){this.insertUI&&(this.container=a.normalizeElement(this.container))},r.prototype._setupPaymentMethodNonceInputField=function(){if(this.insertUI){var t=this.paymentMethodNonceInputField;a.isFunction(t)||(t=void 0!==t?a.normalizeElement(t):this._createPaymentMethodNonceInputField(),this.paymentMethodNonceInputField=t)}},r.prototype._setupViews=function(){var t=this._clientToken.paypal.assetsUrl;this.insertUI&&(this.loggedInView=new u({container:this.container,assetsUrl:t}),this.loggedOutView=new c({assetsUrl:t,container:this.container,isCheckout:this._isAriesCapable(),locale:this._clientOptions.locale,merchantId:"merchantId"}),a.addEventListener(this.loggedOutView.container,"click",a.bind(this._handleContainerClick,this)),a.addEventListener(this.loggedInView.logoutNode,"click",a.bind(this._handleLogout,this)))},r.prototype._createRpcServer=function(){var t=new s.MessageBus(window),e=new s.RPCServer(t,window);e.define("getClientToken",a.bind(this._handleGetClientToken,this)),e.define("getClientOptions",a.bind(this._handleGetClientOptions,this)),e.define("closePayPalModal",a.bind(this._handleCloseMessage,this)),e.define("receivePayPalData",a.bind(this._handleSuccessfulAuthentication,this))},r.prototype._createPaymentMethodNonceInputField=function(){var t=document.createElement("input");return t.name="payment_method_nonce",t.type="hidden",this.container.appendChild(t)},r.prototype._createFrame=function(){var t,e=document.createElement("iframe");return this._isAriesCapable()?(t=d.ARIES_FRAME_NAME,e.style.background="#FFFFFF"):t=d.FRAME_NAME,e.src=this.getViewerUrl(),e.id=t,e.name=t,e.allowTransparency=!0,e.height="100%",e.width="100%",e.frameBorder=0,e.style.position=p.isMobile()?"absolute":"fixed",e.style.top=0,e.style.left=0,e.style.bottom=0,e.style.zIndex=20001,e.style.padding=0,e.style.margin=0,e.style.border=0,e.style.outline="none",e
4
+ },r.prototype._removeFrame=function(t){t=t||document.body,this.frame&&t.contains(this.frame)&&(t.removeChild(this.frame),this._unlockMerchantWindowSize())},r.prototype._insertFrame=function(){this.insertFrameFunction?this.insertFrameFunction(this.getViewerUrl()):(this.frame=this._createFrame(),document.body.appendChild(this.frame)),this._lockMerchantWindowSize()},r.prototype._handleContainerClick=function(t){function e(t){return t.className.match(/paypal-button(?!-widget)/)||"braintree-paypal-button"===t.id}var n=t.target||t.srcElement;(e(n)||e(n.parentNode))&&(t.preventDefault?t.preventDefault():t.returnValue=!1,this._open())},r.prototype._setMerchantPageDefaultStyles=function(){this.merchantPageDefaultStyles=i()},r.prototype._open=function(){this._isAriesCapable()&&this._addCorrelationIdToClientToken(),p.isPopupSupported()?this._openPopup():this._openModal()},r.prototype._close=function(){p.isPopupSupported()?this._closePopup():this._closeModal()},r.prototype._openModal=function(){this._removeFrame(),this._insertFrame()},r.prototype._isAriesCapable=function(){return!(!this._clientOptions.singleUse||!this._clientOptions.amount||!this._clientOptions.currency||this._clientOptions.demo)},r.prototype._openPopup=function(){var t,e,n,i=[],r=window.outerWidth||document.documentElement.clientWidth,o=window.outerHeight||document.documentElement.clientHeight,s="undefined"==typeof window.screenY?window.screenTop:window.screenY,a="undefined"==typeof window.screenX?window.screenLeft:window.screenX;this._isAriesCapable()?(t=d.ARIES_POPUP_NAME,n=d.ARIES_POPUP_HEIGHT,e=d.ARIES_POPUP_WIDTH):(t=d.POPUP_NAME,n=d.POPUP_HEIGHT,e=d.POPUP_WIDTH);var u=(r-e)/2+a,c=(o-n)/2+s;return i.push("height="+n),i.push("width="+e),i.push("top="+c),i.push("left="+u),i.push(d.POPUP_OPTIONS),this.popup=window.open(this.getViewerUrl(),t,i.join(",")),p.isOverlaySupported()&&(this.overlayView=new l(this.popup,this._clientToken.paypal.assetsUrl),this.overlayView.render()),this.popup.focus(),this.popup},r.prototype._addCorrelationIdToClientToken=function(){this._clientToken.correlationId=f.generateUid()},r.prototype._createProxyFrame=function(){var t=document.createElement("iframe");return t.src=this.getProxyUrl(),t.id=d.BRIDGE_FRAME_NAME,t.name=d.BRIDGE_FRAME_NAME,t.allowTransparency=!0,t.height=0,t.width=0,t.frameBorder=0,t.style.position="static",t.style.padding=0,t.style.margin=0,t.style.border=0,t.style.outline="none",t},r.prototype._insertProxyFrame=function(){this.proxyFrame=this._createProxyFrame(),document.body.appendChild(this.proxyFrame)},r.prototype._closeModal=function(){this._removeFrame()},r.prototype._closePopup=function(){this.popup&&(this.popup.close(),this.popup=null),this.overlayView&&p.isOverlaySupported()&&this.overlayView.remove()},r.prototype._clientTokenData=function(){return{analyticsUrl:this._clientToken.analytics?this._clientToken.analytics.url:void 0,authorizationFingerprint:this._clientToken.authorizationFingerprint,authUrl:this._clientToken.authUrl,clientApiUrl:this._clientToken.clientApiUrl,displayName:this._clientToken.paypal.displayName,paypalBaseUrl:this._clientToken.paypal.assetsUrl,paypalClientId:this._clientToken.paypal.clientId,paypalPrivacyUrl:this._clientToken.paypal.privacyUrl,paypalUserAgreementUrl:this._clientToken.paypal.userAgreementUrl,unvettedMerchant:this._clientToken.paypal.unvettedMerchant,payeeEmail:this._clientToken.paypal.payeeEmail,correlationId:this._clientToken.correlationId,offline:this._clientOptions.offline||this._clientToken.paypal.environmentNoNetwork}},r.prototype._handleGetClientToken=function(t){t(this._clientTokenData())},r.prototype._clientOptionsData=function(){return{demo:this._clientOptions.demo||!1,locale:this._clientOptions.locale||"en_us",onetime:this._clientOptions.singleUse||!1,integration:this._clientOptions.integration||"paypal",enableShippingAddress:this._clientOptions.enableShippingAddress||!1,enableAries:this._isAriesCapable(),amount:this._clientOptions.amount||null,currency:this._clientOptions.currency||null,shippingAddressOverride:this._clientOptions.shippingAddressOverride||null}},r.prototype._handleGetClientOptions=function(t){t(this._clientOptionsData())},r.prototype._handleSuccessfulAuthentication=function(t){this._close(),t.type=d.NONCE_TYPE,a.isFunction(this.paymentMethodNonceInputField)?this.paymentMethodNonceInputField(t.nonce):(this._showLoggedInContent(t.details.email),this._setNonceInputValue(t.nonce)),a.isFunction(this.onSuccess)&&this.onSuccess(t)},r.prototype._lockMerchantWindowSize=function(){this._setMerchantPageDefaultStyles(),document.documentElement.style.height="100%",document.documentElement.style.overflow="hidden",document.body.style.height="100%",document.body.style.overflow="hidden"},r.prototype._unlockMerchantWindowSize=function(){this.merchantPageDefaultStyles&&(document.documentElement.style.height=this.merchantPageDefaultStyles.html.styles.height,document.documentElement.style.overflow=this.merchantPageDefaultStyles.html.styles.overflow,document.body.style.height=this.merchantPageDefaultStyles.body.styles.height,document.body.style.overflow=this.merchantPageDefaultStyles.body.styles.overflow)},r.prototype._handleCloseMessage=function(){this._removeFrame()},r.prototype._showLoggedInContent=function(t){this.loggedOutView.hide(),h.setTextContent(this.loggedInView.emailNode,t),this.loggedInView.show()},r.prototype._handleLogout=function(t){t.preventDefault?t.preventDefault():t.returnValue=!1,this.loggedInView.hide(),this.loggedOutView.show(),this._setNonceInputValue(""),a.isFunction(this.onCancelled)&&this.onCancelled()},r.prototype._setNonceInputValue=function(t){this.paymentMethodNonceInputField.value=t},e.exports=r},{"../shared/constants":170,"../shared/get-locale":172,"../shared/util/browser":177,"../shared/util/dom":178,"../shared/util/util":179,"./logged-in-view":167,"./logged-out-view":168,"./overlay-view":169,"braintree-api":120,"braintree-rpc":153,"braintree-utilities":165}],167:[function(t,e){function n(t){this.options=t,this.container=this.createViewContainer(),this.createPayPalName(),this.emailNode=this.createEmailNode(),this.logoutNode=this.createLogoutNode()}var i=t("../shared/constants");n.prototype.createViewContainer=function(){var t=document.createElement("div");t.id="braintree-paypal-loggedin";var e=["display: none","max-width: 500px","overflow: hidden","padding: 16px","background-image: url("+this.options.assetsUrl+"/pwpp/"+i.VERSION+"/images/paypal-small.png)","background-image: url("+this.options.assetsUrl+"/pwpp/"+i.VERSION+"/images/paypal-small.svg), none","background-position: 20px 50%","background-repeat: no-repeat","background-size: 13px 15px","border-top: 1px solid #d1d4d6","border-bottom: 1px solid #d1d4d6"].join(";");return t.style.cssText=e,this.options.container.appendChild(t),t},n.prototype.createPayPalName=function(){var t=document.createElement("span");t.id="bt-pp-name",t.innerHTML="PayPal";var e=["color: #283036","font-size: 13px","font-weight: 800",'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',"margin-left: 36px","-webkit-font-smoothing: antialiased","-moz-font-smoothing: antialiased","-ms-font-smoothing: antialiased","font-smoothing: antialiased"].join(";");return t.style.cssText=e,this.container.appendChild(t)},n.prototype.createEmailNode=function(){var t=document.createElement("span");t.id="bt-pp-email";var e=["color: #6e787f","font-size: 13px",'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',"margin-left: 5px","-webkit-font-smoothing: antialiased","-moz-font-smoothing: antialiased","-ms-font-smoothing: antialiased","font-smoothing: antialiased"].join(";");return t.style.cssText=e,this.container.appendChild(t)},n.prototype.createLogoutNode=function(){var t=document.createElement("button");t.id="bt-pp-cancel",t.innerHTML="Cancel";var e=["color: #3d95ce","font-size: 11px",'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',"line-height: 20px","margin: 0 0 0 25px","padding: 0","background-color: transparent","border: 0","cursor: pointer","text-decoration: underline","float: right","-webkit-font-smoothing: antialiased","-moz-font-smoothing: antialiased","-ms-font-smoothing: antialiased","font-smoothing: antialiased"].join(";");return t.style.cssText=e,this.container.appendChild(t)},n.prototype.show=function(){this.container.style.display="block"},n.prototype.hide=function(){this.container.style.display="none"},e.exports=n},{"../shared/constants":170}],168:[function(t,e){function n(t){this.options=t,this.assetsUrl=this.options.assetsUrl,this.container=this.createViewContainer(),this.options.isCheckout?this.createCheckoutWithPayPalButton():this.createPayWithPayPalButton()}var i=(t("braintree-utilities"),t("../shared/constants")),r=t("../shared/get-locale");n.prototype.createViewContainer=function(){var t=document.createElement("div");return t.id="braintree-paypal-loggedout",this.options.container.appendChild(t),t},n.prototype.createPayWithPayPalButton=function(){var t=document.createElement("a");t.id="braintree-paypal-button",t.href="#";var e=["display: block","width: 115px","height: 44px","overflow: hidden"].join(";");t.style.cssText=e;var n=new Image;n.src=this.assetsUrl+"/pwpp/"+i.VERSION+"/images/pay-with-paypal.png",n.setAttribute("alt","Pay with PayPal");var r=["max-width: 100%","display: block","width: 100%","height: 100%","outline: none","border: 0"].join(";");n.style.cssText=r,t.appendChild(n),this.container.appendChild(t)},n.prototype.createCheckoutWithPayPalButton=function(){var t=document.createElement("script");t.src="//www.paypalobjects.com/api/button.js",t.async=!0,t.setAttribute("data-merchant",this.options.merchantId),t.setAttribute("data-button","checkout"),t.setAttribute("data-type","button"),t.setAttribute("data-width","150"),t.setAttribute("data-height","44"),t.setAttribute("data-lc",r(this.options.locale)),this.container.appendChild(t)},n.prototype.show=function(){this.container.style.display="block"},n.prototype.hide=function(){this.container.style.display="none"},e.exports=n},{"../shared/constants":170,"../shared/get-locale":172,"braintree-utilities":165}],169:[function(t,e){function n(t,e){this.popup=t,this.assetsUrl=e,this.spriteSrc=this.assetsUrl+"/pwpp/"+r.VERSION+"/images/pp_overlay_sprite.png",this._create(),this._setupEvents(),this._pollForPopup()}var i=t("braintree-utilities"),r=t("../shared/constants");n.prototype.render=function(){document.body.contains(this.el)||document.body.appendChild(this.el)},n.prototype.remove=function(){document.body.contains(this.el)&&document.body.removeChild(this.el)},n.prototype._create=function(){this.el=document.createElement("div"),this.el.className="bt-overlay",this._setStyles(this.el,["z-index: 20001","position: fixed","top: 0","left: 0","height: 100%","width: 100%","text-align: center","background: #000","background: rgba(0,0,0,0.7)",'-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=52)"']),this.el.appendChild(this._createCloseIcon()),this.el.appendChild(this._createMessage())},n.prototype._createCloseIcon=function(){return this.closeIcon=document.createElement("div"),this.closeIcon.className="bt-close-overlay",this._setStyles(this.closeIcon,["position: absolute","top: 10px","right: 10px","cursor: pointer","background: url("+this.spriteSrc+") no-repeat 0 -67px","height: 14px","width: 14px"]),this.closeIcon},n.prototype._createMessage=function(){var t=document.createElement("div");return this._setStyles(t,["position: relative","top: 50%","max-width: 350px",'font-family: "HelveticaNeue", "HelveticaNeue-Light", "Helvetica Neue Light", helvetica, arial, sans-serif',"font-size: 14px","line-height: 20px","margin: -70px auto 0"]),t.appendChild(this._createLogo()),t.appendChild(this._createExplanation()),t.appendChild(this._createFocusLink()),t},n.prototype._createExplanation=function(){var t=document.createElement("div");return this._setStyles(t,["color: #FFF","margin-bottom: 20px"]),t.innerHTML="Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",t},n.prototype._createLogo=function(){var t=document.createElement("div");return this._setStyles(t,["background: url("+this.spriteSrc+") no-repeat 0 0","width: 94px","height: 25px","margin: 0 auto 26px auto"]),t},n.prototype._createFocusLink=function(){return this.focusLink=document.createElement("a"),this._setStyles(this.focusLink,["color: #009be1","cursor: pointer"]),this.focusLink.innerHTML="Continue",this.focusLink},n.prototype._setStyles=function(t,e){var n=e.join(";");t.style.cssText=n},n.prototype._setupEvents=function(){i.addEventListener(this.closeIcon,"click",i.bind(this._handleClose,this)),i.addEventListener(this.focusLink,"click",i.bind(this._handleFocus,this))},n.prototype._handleClose=function(t){t.preventDefault(),this.remove(),this.popup.close()},n.prototype._handleFocus=function(t){t.preventDefault(),this.popup.focus()},n.prototype._pollForPopup=function(){var t=setInterval(i.bind(function(){this.popup&&this.popup.closed&&(clearInterval(t),this.remove())},this),100)},e.exports=n},{"../shared/constants":170,"braintree-utilities":165}],170:[function(t,e,n){var i="1.3.4";n.VERSION=i,n.POPUP_NAME="braintree_paypal_popup",n.ARIES_POPUP_NAME="PPFrameRedirect",n.FRAME_NAME="braintree-paypal-frame",n.ARIES_FRAME_NAME="PPFrameRedirect",n.POPUP_PATH="/pwpp/"+i+"/html/braintree-frame.html",n.POPUP_OPTIONS="resizable,scrollbars",n.POPUP_HEIGHT=470,n.POPUP_WIDTH=410,n.ARIES_POPUP_HEIGHT=535,n.ARIES_POPUP_WIDTH=450,n.BRIDGE_FRAME_NAME="bt-proxy-frame",n.ARIES_SUPPORTED_CURRENCIES=["USD","GBP","EUR","AUD","CAD"],n.ARIES_SUPPORTED_COUNTRIES=["US","GB","AU","CA","ES","FR","DE","IT"],n.NONCE_TYPE="PayPalAccount",n.ILLEGAL_XHR_ERROR="Illegal XHR request attempted"},{}],171:[function(t,e){"use strict";e.exports={us:"en_us",gb:"en_uk",uk:"en_uk",de:"de_de",fr:"fr_fr",it:"it_it",es:"es_es",ca:"en_ca",au:"en_au",at:"de_de",be:"en_us",ch:"de_de",dk:"da_dk",nl:"nl_nl",no:"no_no",pl:"pl_pl",se:"sv_se",tr:"tr_tr",bg:"en_us",cy:"en_us",hr:"en_us",is:"en_us",kh:"en_us",mt:"en_us",my:"en_us",ru:"ru_ru"}},{}],172:[function(t,e){"use strict";function n(t){return-1!==t.indexOf("_")&&5===t.length}function i(t){var e;for(var n in o)o.hasOwnProperty(n)&&(n===t?e=o[n]:o[n]===t&&(e=o[n]));return e}function r(t){var e;if(t=t?t.toLowerCase():"us",t=t.replace(/-/g,"_"),e=n(t)?t:i(t)){var r=e.split("_");return[r[0],r[1].toUpperCase()].join("_")}return"en_US"}var o=t("../shared/data/country-code-lookup");e.exports=r},{"../shared/data/country-code-lookup":171}],173:[function(t,e){function n(){return c.matchUserAgent("Android")&&!i()}function i(){return c.matchUserAgent("Chrome")||c.matchUserAgent("CriOS")}function r(){return c.matchUserAgent("Firefox")}function o(){return c.matchUserAgent("Trident")||c.matchUserAgent("MSIE")}function s(){return c.matchUserAgent("Opera")||c.matchUserAgent("OPR")}function a(){return s()&&"[object OperaMini]"===l.call(window.operamini)}function u(){return c.matchUserAgent("Safari")&&!i()&&!n()}var c=t("./useragent"),l=Object.prototype.toString;e.exports={isAndroid:n,isChrome:i,isFirefox:r,isIE:o,isOpera:s,isOperaMini:a,isSafari:u}},{"./useragent":176}],174:[function(t,e){function n(){return!i()&&(s.isAndroid()||s.isIpod()||s.isIphone()||o.matchUserAgent("IEMobile"))}function i(){return s.isIpad()||s.isAndroid()&&!o.matchUserAgent("Mobile")}function r(){return!n()&&!i()}var o=t("./useragent"),s=t("./platform");e.exports={isMobile:n,isTablet:i,isDesktop:r}},{"./platform":175,"./useragent":176}],175:[function(t,e){function n(){return a.matchUserAgent("Android")}function i(){return a.matchUserAgent("iPad")}function r(){return a.matchUserAgent("iPod")}function o(){return a.matchUserAgent("iPhone")&&!r()}function s(){return i()||r()||o()}var a=t("./useragent");e.exports={isAndroid:n,isIpad:i,isIpod:r,isIphone:o,isIos:s}},{"./useragent":176}],176:[function(t,e,n){function i(){return o}function r(t){var e=n.getNativeUserAgent(),i=e.match(t);return i?!0:!1}var o=window.navigator.userAgent;n.getNativeUserAgent=i,n.matchUserAgent=r},{}],177:[function(t,e){function n(){return i()&&window.outerWidth<600}function i(){return f.test(d)}function r(){return!!window.postMessage}function o(){if(c.isOperaMini())return!1;if(l.isDesktop())return!0;if(l.isMobile()||l.isTablet()){if(c.isIE())return!1;if(p.isAndroid())return!0;if(p.isIos())return c.isSafari()&&h.matchUserAgent(/OS (?:8_1|8_0|8)(?!_\d)/i)||c.isChrome()?!1:!0}return!1}function s(){if(c.isIE()&&h.matchUserAgent(/MSIE 8\.0/))return!1;try{return window.self===window.top}catch(t){return!1}}function a(){return c.isIE()&&!u()}function u(){var t=null,e="";try{new ActiveXObject("")}catch(n){e=n.name}try{t=!!new ActiveXObject("htmlfile")}catch(n){t=!1}return t="ReferenceError"!==e&&t===!1?!1:!0,!t}var c=t("../useragent/browser"),l=t("../useragent/device"),p=t("../useragent/platform"),h=t("../useragent/useragent"),d=window.navigator.userAgent,f=/[Mm]obi|tablet|iOS|Android|IEMobile|Windows\sPhone/;e.exports={isMobile:n,isMobileDevice:i,detectedPostMessage:r,isPopupSupported:o,isOverlaySupported:s,isProxyFrameRequired:a}},{"../useragent/browser":173,"../useragent/device":174,"../useragent/platform":175,"../useragent/useragent":176}],178:[function(t,e){function n(t,e){var n="innerText";document&&document.body&&"textContent"in document.body&&(n="textContent"),t[n]=e}e.exports={setTextContent:n}},{}],179:[function(t,e){function n(){for(var t="",e=0;32>e;e++){var n=Math.floor(16*Math.random());t+=n.toString(16)}return t}function i(t){return/^(true|1)$/i.test(t)}function r(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;").replace(/\'/g,"&apos;")}function o(t){var e=t.indexOf("?"),n={};if(e>=0&&(t=t.substr(e+1)),0!==t.length){for(var i=t.split("&"),r=0,o=i.length;o>r;r++){var s=i[r],a=s.indexOf("="),u=s.substr(0,a),c=s.substr(a+1),l=decodeURIComponent(c);l=l.replace(/</g,"&lt;").replace(/>/g,"&gt;"),"false"===l&&(l=!1),(void 0===l||"true"===l)&&(l=!0),n[u]=l}return n}}function s(t){return t&&"[object Function]"===Object.prototype.toString.call(t)}var a="function"==typeof String.prototype.trim?function(t){return t.trim()}:function(t){return t.replace(/^\s+|\s+$/,"")},u="function"==typeof window.btoa?function(t){return window.btoa(t)}:function(t){for(var e,n,i,r,o,s,a,u="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",c="",l=0;l<t.length;)e=t.charCodeAt(l++),n=t.charCodeAt(l++),i=t.charCodeAt(l++),r=e>>2,o=(3&e)<<4|n>>4,s=(15&n)<<2|i>>6,a=63&i,isNaN(n)?s=a=64:isNaN(i)&&(a=64),c=c+u.charAt(r)+u.charAt(o)+u.charAt(s)+u.charAt(a);return c};e.exports={trim:a,btoa:u,generateUid:n,castToBoolean:i,htmlEscape:r,parseUrlParams:o,isFunction:s}},{}],180:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":190,dup:25}],181:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":190,dup:26}],182:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],183:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":190,dup:28}],184:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":190,dup:29}],185:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":180,"./lib/pubsub-client":181,"./lib/pubsub-server":182,"./lib/rpc-client":183,"./lib/rpc-server":184,dup:30}],186:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],187:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],188:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],189:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],190:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":186,"./lib/events":187,"./lib/fn":188,"./lib/url":189,dup:19}],191:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],192:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],193:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],194:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],195:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":191,"./lib/events":192,"./lib/fn":193,"./lib/url":194,dup:19}],196:[function(t,e){"use strict";function n(t){this.apiClient=t}var i=["getCreditCards","unlockCreditCard","sendAnalyticsEvents"];n.prototype.attach=function(t){function e(e){t.define(e,function(){n.apiClient[e].apply(n.apiClient,arguments)})}var n=this,r=0,o=i.length;for(r;o>r;r++)e(i[r])},e.exports=n},{}],197:[function(t,e){"use strict";function n(t,e){var n=window.getComputedStyle?getComputedStyle(t):t.currentStyle;return n[e]}function i(){return{html:{height:s.style.height||"",overflow:n(s,"overflow"),position:n(s,"position")},body:{height:a.style.height||"",overflow:n(a,"overflow")}}}function r(){var t=/Android|iPhone|iPod|iPad/i.test(window.navigator.userAgent);return t}function o(t){var e,n,i;this.encodedClientToken=t.clientToken,this.paypalOptions=t.paypal,this.container=null,this.merchantFormManager=null,this.root=t.root,this.configurationRequests=[],this.braintreeApiClient=u.configure({clientToken:t.clientToken,integration:"dropin"}),this.paymentMethodNonceReceivedCallback=t.paymentMethodNonceReceived,this.clientToken=u.parseClientToken(t.clientToken),this.bus=new l.MessageBus(this.root),this.rpcServer=new l.RPCServer(this.bus),this.apiProxyServer=new h(this.braintreeApiClient),this.apiProxyServer.attach(this.rpcServer),e=t.inlineFramePath||this.clientToken.assetsUrl+"/dropin/"+g+"/inline-frame.html",n=t.modalFramePath||this.clientToken.assetsUrl+"/dropin/"+g+"/modal-frame.html",s=document.documentElement,a=document.body,this.frames={inline:this._createFrame(e,"braintree-dropin-frame"),modal:this._createFrame(n,"braintree-dropin-modal-frame")},this.container=p.normalizeElement(t.container,"Unable to find valid container."),i=p.normalizeElement(t.form||this._findClosest(this.container,"form")),this.merchantFormManager=new d({form:i,frames:this.frames,onSubmit:this.paymentMethodNonceReceivedCallback,apiClient:this.braintreeApiClient}).initialize(),this.clientToken.paypalEnabled&&this.clientToken.paypal&&(p.isBrowserHttps()||this.clientToken.paypal.allowHttp)&&this._configurePayPal(),this.braintreeApiClient.sendAnalyticsEvents("dropin.web.initialized")}var s,a,u=t("braintree-api"),c=t("braintree-bus"),l=t("braintree-rpc"),p=t("braintree-utilities"),h=t("./api-proxy-server"),d=t("./merchant-form-manager"),f=t("./frame-container"),m=t("../shared/paypal-service"),y=t("braintree-paypal/src/shared/util/browser"),g="1.3.7";o.prototype.initialize=function(){var t=this;this._initializeModal(),this.container.appendChild(this.frames.inline.element),a.appendChild(this.frames.modal.element),this.rpcServer.define("receiveSharedCustomerIdentifier",function(e){t.braintreeApiClient.attrs.sharedCustomerIdentifier=e,t.braintreeApiClient.attrs.sharedCustomerIdentifierType="browser_session_cookie_store";for(var n=0;n<t.configurationRequests.length;n++)t.configurationRequests[n](t.encodedClientToken);t.configurationRequests=[]}),c.on(c.events.PAYMENT_METHOD_GENERATED,p.bind(this._handleAltPayData,this)),this.rpcServer.define("getConfiguration",function(e){e({clientToken:t.encodedClientToken,merchantHttps:p.isBrowserHttps()})}),this.rpcServer.define("getPayPalOptions",function(e){e(t.paypalOptions)}),this.rpcServer.define("selectPaymentMethod",function(e){t.frames.modal.rpcClient.invoke("selectPaymentMethod",[e]),t._showModal()}),this.rpcServer.define("sendAddedPaymentMethod",function(e){t.merchantFormManager.setNoncePayload(e),t.frames.inline.rpcClient.invoke("receiveNewPaymentMethod",[e])}),this.rpcServer.define("sendUsedPaymentMethod",function(e){t.frames.inline.rpcClient.invoke("selectPaymentMethod",[e])}),this.rpcServer.define("sendUnlockedNonce",function(e){t.merchantFormManager.setNoncePayload(e)}),this.rpcServer.define("clearNonce",function(){t.merchantFormManager.clearNoncePayload()}),this.rpcServer.define("closeDropInModal",function(){t._hideModal()}),this.rpcServer.define("setInlineFrameHeight",function(e){t.frames.inline.element.style.height=e+"px"}),this.bus.register("ready",function(e){e.source===t.frames.inline.element.contentWindow?t.frames.inline.rpcClient=new l.RPCClient(t.bus,e.source):e.source===t.frames.modal.element.contentWindow&&(t.frames.modal.rpcClient=new l.RPCClient(t.bus,e.source))})},o.prototype._createFrame=function(t,e){return new f(t,e)},o.prototype._initializeModal=function(){this.frames.modal.element.style.display="none",this.frames.modal.element.style.position=r()?"absolute":"fixed",this.frames.modal.element.style.top="0",this.frames.modal.element.style.left="0",this.frames.modal.element.style.height="100%",this.frames.modal.element.style.width="100%"},o.prototype._lockMerchantWindowSize=function(){setTimeout(function(){s.style.overflow="hidden",a.style.overflow="hidden",a.style.height="100%",r()&&(s.style.position="relative",s.style.height=window.innerHeight+"px")},160)},o.prototype._unlockMerchantWindowSize=function(){var t=this.merchantPageDefaultStyles;a.style.height=t.body.height,a.style.overflow=t.body.overflow,s.style.overflow=t.html.overflow,r()&&(s.style.height=t.html.height,s.style.position=t.html.position)},o.prototype._showModal=function(){var t=this,e=this.frames.modal.element;this.merchantPageDefaultStyles=i(),e.style.display="block",this.frames.modal.rpcClient.invoke("open",[],function(){setTimeout(function(){t._lockMerchantWindowSize(),e.contentWindow.focus()},200)})},o.prototype._hideModal=function(){this._unlockMerchantWindowSize(),this.frames.modal.element.style.display="none"},o.prototype._configurePayPal=function(){y.isPopupSupported()||(this.ppClient=new m({clientToken:this.clientToken,paypal:this.paypalOptions}),this.rpcServer.define("openPayPalModal",p.bind(this.ppClient._openModal,this.ppClient))),this.rpcServer.define("receivePayPalData",p.bind(this._handleAltPayData,this))},o.prototype._handleAltPayData=function(t){this.merchantFormManager.setNoncePayload(t),this.frames.inline.rpcClient.invoke("receiveNewPaymentMethod",[t]),this.frames.modal.rpcClient.invoke("modalViewClose")},o.prototype._findClosest=function(t,e){e=e.toUpperCase();do if(t.nodeName===e)return t;while(t=t.parentNode);throw"Unable to find a valid "+e},e.exports=o},{"../shared/paypal-service":201,"./api-proxy-server":196,"./frame-container":199,"./merchant-form-manager":200,"braintree-api":77,"braintree-bus":105,"braintree-paypal/src/shared/util/browser":177,"braintree-rpc":185,"braintree-utilities":195}],198:[function(t,e){"use strict";function n(t,e){e.clientToken=t;var n=new i(e);return n.initialize(),n}var i=t("./client"),r="1.3.7";e.exports={create:n,VERSION:r}},{"./client":197}],199:[function(t,e){"use strict";function n(t,e){this.element=document.createElement("iframe"),this.element.setAttribute("name",e),this.element.setAttribute("allowtransparency","true"),this.element.setAttribute("width","100%"),this.element.setAttribute("height","68"),this.element.setAttribute("style","-webkit-transition: height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000); -moz-transition: height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000); -ms-transition: height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000); -o-transition: height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000); transition: height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000);"),this.element.src=t,this.element.setAttribute("frameborder","0"),this.element.setAttribute("allowtransparency","true"),this.element.style.border="0",this.element.style.zIndex="9999"}e.exports=n},{}],200:[function(t,e){"use strict";function n(t){this.form=t.form,this.frames=t.frames,this.onSubmit=t.onSubmit,this.apiClient=t.apiClient}var i=t("braintree-utilities");n.prototype.initialize=function(){return this._isSubmitBased()&&this._setElements(),this._setEvents(),this},n.prototype.setNoncePayload=function(t){this.noncePayload=t},n.prototype.clearNoncePayload=function(){this.noncePayload=null},n.prototype._isSubmitBased=function(){return!this.onSubmit},n.prototype._isCallbackBased=function(){return!!this.onSubmit},n.prototype._setElements=function(){if(!this.form.payment_method_nonce){var t=document.createElement("input");t.type="hidden",t.name="payment_method_nonce",this.form.appendChild(t)}this.nonceField=this.form.payment_method_nonce},n.prototype._setEvents=function(){var t=this;i.addEventListener(this.form,"submit",function(){t._handleFormSubmit.apply(t,arguments)})},n.prototype._handleFormSubmit=function(t){this._shouldSubmit()||(t&&t.preventDefault?t.preventDefault():t.returnValue=!1,this.noncePayload&&this.noncePayload.nonce?this._handleNonceReply(t):this.frames.inline.rpcClient.invoke("requestNonce",[],i.bind(function(e){this.setNoncePayload(e),this._handleNonceReply(t)},this)))},n.prototype._shouldSubmit=function(){return this._isCallbackBased()?!1:this.nonceField.value.length>0},n.prototype._handleNonceReply=function(t){this._isCallbackBased()?this.apiClient.sendAnalyticsEvents("dropin.web.end.callback",i.bind(function(){var e=this.noncePayload;e.originalEvent=t,this.onSubmit(e),setTimeout(i.bind(function(){this.frames.inline.rpcClient.invoke("clearLoadingState")},this),200)},this)):this._triggerFormSubmission()},n.prototype._triggerFormSubmission=function(){this.nonceField.value=this.noncePayload.nonce,this.apiClient.sendAnalyticsEvents("dropin.web.end.auto-submit",i.bind(function(){"function"==typeof this.form.submit?this.form.submit():this.form.querySelector('[type="submit"]').click()},this))},e.exports=n},{"braintree-utilities":195}],201:[function(t,e){"use strict";function n(t){var e=t.clientToken,n=t.paypal||{},r=new i(e,{container:document.createElement("div"),displayName:n.displayName,locale:n.locale,singleUse:n.singleUse,amount:n.amount,currency:n.currency,onSuccess:n.onSuccess,enableShippingAddress:n.enableShippingAddress,shippingAddressOverride:n.shippingAddressOverride});return r.initialize(),r}var i=t("braintree-paypal/src/external/client");e.exports=n},{"braintree-paypal/src/external/client":166}],202:[function(t,e){"use strict";function n(t,e,n){this.client=t,this.htmlForm=e,this.paymentMethodNonceInput=n,this.setNonce({}),this.hijackForm()}var i=t("braintree-utilities");n.prototype.hijackForm=function(){this.onSubmitHandler=i.bind(this.handleSubmit,this),i.addEventListener(this.htmlForm,"submit",this.onSubmitHandler)},n.prototype.handleSubmit=function(t){var e=this;return t.preventDefault?t.preventDefault():t.returnValue=!1,this.hasExternalNonce()?(this.scrubAllAttributes(),void this.onNonceReceived(null,this.getNonce())):void this.client.tokenizeCard(this.extractValues(),function(t,n,i){t||e.setNonce({nonce:n,type:i.type,details:i.details}),e.onNonceReceived(t,e.getNonce())})},n.prototype.setNonce=function(t){this.nonce=t},n.prototype.getNonce=function(){return this.nonce},n.prototype.writeNonceToDOM=function(){this.paymentMethodNonceInput.value=this.getNonce().nonce},n.prototype.isBraintreeNode=function(t){return 1===t.nodeType&&t.attributes["data-braintree-name"]},n.prototype.hasExternalNonce=function(){var t=this.getNonce(),e=t&&null!=t.type&&"CreditCard"!==t.type,n=this.htmlForm.querySelector('[data-braintree-name="number"]').value.length<1;return n&&t&&t.nonce&&e},n.prototype.onExternalNonceReceived=function(t){this.clearCardNumberInput(),this.setNonce(t)},n.prototype.onExternalNonceCancelled=function(){this.setNonce(null)},n.prototype.onNonceReceived=function(t){var e=this.htmlForm;if(t)throw new Error("Unable to process payments at this time.");i.removeEventListener(e,"submit",this.onSubmitHandler),this.writeNonceToDOM(),e.submit&&("function"==typeof e.submit||e.submit.call)?e.submit():setTimeout(function(){e.querySelector('[type="submit"]').click()},1)},n.prototype.scrubAllAttributes=function(){this.extractValues()},n.prototype.extractValues=function(t,e){e=e||{},t=t||this.htmlForm;var n,i,r=t.children;for(i=0;i<r.length;i++)if(n=r[i],this.isBraintreeNode(n)){var o=n.getAttribute("data-braintree-name");"postal_code"===o?e.billingAddress={postalCode:n.value}:e[o]=n.value,this.scrubAttributes(n)
5
+ }else n.children&&n.children.length>0&&this.extractValues(n,e);return e},n.prototype.scrubAttributes=function(t){try{t.attributes.removeNamedItem("name")}catch(e){}},n.prototype.clearCardNumberInput=function(){var t=this.htmlForm.querySelector('[data-braintree-name="number"]');t.value=""},e.exports=n},{"braintree-utilities":210}],203:[function(t,e){"use strict";e.exports=function(t){var e;if("object"==typeof t)return t;e="payment_method_nonce","string"==typeof t&&(e=t);var n=document.createElement("input");return n.name=e,n.type="hidden",n}},{}],204:[function(t,e){"use strict";e.exports=function(t){for(var e=t.getElementsByTagName("*"),n={},i=0;i<e.length;i++){var r=e[i].getAttribute("data-braintree-name");n[r]=!0}if(!n.number)throw new Error('Unable to find an input with data-braintree-name="number" in your form. Please add one.');if(n.expiration_date){if(n.expiration_month||n.expiration_year)throw new Error('You have inputs with data-braintree-name="expiration_date" AND data-braintree-name="expiration_(year|month)". Please use either "expiration_date" or "expiration_year" and "expiration_month".')}else{if(!n.expiration_month&&!n.expiration_year)throw new Error('Unable to find an input with data-braintree-name="expiration_date" in your form. Please add one.');if(!n.expiration_month)throw new Error('Unable to find an input with data-braintree-name="expiration_month" in your form. Please add one.');if(!n.expiration_year)throw new Error('Unable to find an input with data-braintree-name="expiration_year" in your form. Please add one.')}}},{}],205:[function(t,e){"use strict";function n(t,e){var n,s,a=document.getElementById(e.id);if(!a)throw new Error('Unable to find form with id: "'+e.id+'"');return r(a),n=o(e.paymentMethodNonceInputField),a.appendChild(n),s=new i(t,a,n)}var i=t("./lib/form"),r=t("./lib/validate-annotations"),o=t("./lib/get-nonce-input");e.exports={setup:n}},{"./lib/form":202,"./lib/get-nonce-input":203,"./lib/validate-annotations":204}],206:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],207:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],208:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],209:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],210:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":206,"./lib/events":207,"./lib/fn":208,"./lib/url":209,dup:19}],211:[function(t,e,n){arguments[4][2][0].apply(n,arguments)},{"./coinbase-account":212,"./credit-card":213,"./jsonp-driver":214,"./normalize-api-fields":216,"./parse-client-token":217,"./root-data":219,"./sepa-bank-account":220,"./sepa-mandate":221,"./util":222,"braintree-3ds":231,"braintree-utilities":250,dup:2}],212:[function(t,e,n){arguments[4][3][0].apply(n,arguments)},{dup:3}],213:[function(t,e,n){arguments[4][4][0].apply(n,arguments)},{dup:4}],214:[function(t,e,n){arguments[4][5][0].apply(n,arguments)},{"./jsonp":215,dup:5}],215:[function(t,e,n){arguments[4][6][0].apply(n,arguments)},{"./util":222,dup:6}],216:[function(t,e,n){arguments[4][7][0].apply(n,arguments)},{dup:7}],217:[function(t,e,n){arguments[4][8][0].apply(n,arguments)},{"./polyfill":218,dup:8}],218:[function(t,e,n){arguments[4][9][0].apply(n,arguments)},{dup:9}],219:[function(t,e,n){arguments[4][10][0].apply(n,arguments)},{"braintree-rpc":239,dup:10}],220:[function(t,e,n){arguments[4][11][0].apply(n,arguments)},{dup:11}],221:[function(t,e,n){arguments[4][12][0].apply(n,arguments)},{dup:12}],222:[function(t,e,n){arguments[4][13][0].apply(n,arguments)},{dup:13}],223:[function(t,e,n){arguments[4][14][0].apply(n,arguments)},{"./lib/client":211,"./lib/jsonp":215,"./lib/jsonp-driver":214,"./lib/parse-client-token":217,"./lib/util":222,dup:14}],224:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],225:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],226:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],227:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],228:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":224,"./lib/events":225,"./lib/fn":226,"./lib/url":227,dup:19}],229:[function(t,e,n){arguments[4][20][0].apply(n,arguments)},{"../shared/receiver":233,"braintree-utilities":228,dup:20}],230:[function(t,e,n){arguments[4][21][0].apply(n,arguments)},{"./authorization_service":229,"braintree-utilities":228,dup:21}],231:[function(t,e,n){arguments[4][22][0].apply(n,arguments)},{"./client":230,"./vendor/json2":232,dup:22}],232:[function(t,e,n){arguments[4][23][0].apply(n,arguments)},{dup:23}],233:[function(t,e,n){arguments[4][24][0].apply(n,arguments)},{"braintree-utilities":228,dup:24}],234:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":244,dup:25}],235:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":244,dup:26}],236:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],237:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":244,dup:28}],238:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":244,dup:29}],239:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":234,"./lib/pubsub-client":235,"./lib/pubsub-server":236,"./lib/rpc-client":237,"./lib/rpc-server":238,dup:30}],240:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],241:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],242:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],243:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],244:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":240,"./lib/events":241,"./lib/fn":242,"./lib/url":243,dup:19}],245:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],246:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],247:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],248:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],249:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],250:[function(t,e,n){arguments[4][41][0].apply(n,arguments)},{"./lib/dom":245,"./lib/events":246,"./lib/fn":247,"./lib/string":248,"./lib/url":249,dup:41}],251:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":261,dup:25}],252:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":261,dup:26}],253:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],254:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":261,dup:28}],255:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":261,dup:29}],256:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":251,"./lib/pubsub-client":252,"./lib/pubsub-server":253,"./lib/rpc-client":254,"./lib/rpc-server":255,dup:30}],257:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],258:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],259:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],260:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],261:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":257,"./lib/events":258,"./lib/fn":259,"./lib/url":260,dup:19}],262:[function(t,e,n){arguments[4][159][0].apply(n,arguments)},{dup:159}],263:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],264:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],265:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],266:[function(t,e,n){arguments[4][39][0].apply(n,arguments)},{dup:39}],267:[function(t,e,n){arguments[4][164][0].apply(n,arguments)},{"./array":262,dup:164}],268:[function(t,e,n){arguments[4][165][0].apply(n,arguments)},{"./lib/array":262,"./lib/dom":263,"./lib/events":264,"./lib/fn":265,"./lib/string":266,"./lib/url":267,dup:165}],269:[function(t,e,n){arguments[4][166][0].apply(n,arguments)},{"../shared/constants":274,"../shared/get-locale":276,"../shared/util/browser":281,"../shared/util/dom":282,"../shared/util/util":283,"./logged-in-view":271,"./logged-out-view":272,"./overlay-view":273,"braintree-api":223,"braintree-rpc":256,"braintree-utilities":268,dup:166}],270:[function(t,e){function n(t,e){if(!r.detectedPostMessage())return void("function"==typeof e.onUnsupported&&e.onUnsupported(new Error("unsupported browser detected")));var n=new i(t,e);return n.initialize(),n}var i=t("./client"),r=t("../shared/util/browser"),o="1.3.4";e.exports={create:n,_browser:r,VERSION:o}},{"../shared/util/browser":281,"./client":269}],271:[function(t,e,n){arguments[4][167][0].apply(n,arguments)},{"../shared/constants":274,dup:167}],272:[function(t,e,n){arguments[4][168][0].apply(n,arguments)},{"../shared/constants":274,"../shared/get-locale":276,"braintree-utilities":268,dup:168}],273:[function(t,e,n){arguments[4][169][0].apply(n,arguments)},{"../shared/constants":274,"braintree-utilities":268,dup:169}],274:[function(t,e,n){arguments[4][170][0].apply(n,arguments)},{dup:170}],275:[function(t,e,n){arguments[4][171][0].apply(n,arguments)},{dup:171}],276:[function(t,e,n){arguments[4][172][0].apply(n,arguments)},{"../shared/data/country-code-lookup":275,dup:172}],277:[function(t,e,n){arguments[4][173][0].apply(n,arguments)},{"./useragent":280,dup:173}],278:[function(t,e,n){arguments[4][174][0].apply(n,arguments)},{"./platform":279,"./useragent":280,dup:174}],279:[function(t,e,n){arguments[4][175][0].apply(n,arguments)},{"./useragent":280,dup:175}],280:[function(t,e,n){arguments[4][176][0].apply(n,arguments)},{dup:176}],281:[function(t,e,n){arguments[4][177][0].apply(n,arguments)},{"../useragent/browser":277,"../useragent/device":278,"../useragent/platform":279,"../useragent/useragent":280,dup:177}],282:[function(t,e,n){arguments[4][178][0].apply(n,arguments)},{dup:178}],283:[function(t,e,n){arguments[4][179][0].apply(n,arguments)},{dup:179}],284:[function(t,e,n){arguments[4][25][0].apply(n,arguments)},{"braintree-utilities":294,dup:25}],285:[function(t,e,n){arguments[4][26][0].apply(n,arguments)},{"braintree-utilities":294,dup:26}],286:[function(t,e,n){arguments[4][27][0].apply(n,arguments)},{dup:27}],287:[function(t,e,n){arguments[4][28][0].apply(n,arguments)},{"braintree-utilities":294,dup:28}],288:[function(t,e,n){arguments[4][29][0].apply(n,arguments)},{"braintree-utilities":294,dup:29}],289:[function(t,e,n){arguments[4][30][0].apply(n,arguments)},{"./lib/message-bus":284,"./lib/pubsub-client":285,"./lib/pubsub-server":286,"./lib/rpc-client":287,"./lib/rpc-server":288,dup:30}],290:[function(t,e,n){arguments[4][31][0].apply(n,arguments)},{dup:31}],291:[function(t,e,n){arguments[4][32][0].apply(n,arguments)},{dup:32}],292:[function(t,e,n){arguments[4][33][0].apply(n,arguments)},{dup:33}],293:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],294:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":290,"./lib/events":291,"./lib/fn":292,"./lib/url":293,dup:19}],295:[function(t,e,n){arguments[4][15][0].apply(n,arguments)},{dup:15}],296:[function(t,e,n){arguments[4][16][0].apply(n,arguments)},{dup:16}],297:[function(t,e,n){arguments[4][17][0].apply(n,arguments)},{dup:17}],298:[function(t,e,n){arguments[4][18][0].apply(n,arguments)},{dup:18}],299:[function(t,e,n){arguments[4][19][0].apply(n,arguments)},{"./lib/dom":295,"./lib/events":296,"./lib/fn":297,"./lib/url":298,dup:19}],300:[function(t,e){function n(t){var e={};if(t){for(var n in t)t.hasOwnProperty(n)&&(e[i(n)]=t[n]);return e}}function i(t){return t.replace(/([A-Z])/g,function(t){return"_"+t.toLowerCase()})}e.exports={convertToLegacyShippingAddress:n}},{}],301:[function(t,e){"use strict";e.exports={ROOT_SUCCESS_CALLBACK:"onPaymentMethodReceived",ROOT_ERROR_CALLBACK:"onError"}},{}],302:[function(t,e){"use strict";function n(t,e){return o.on(o.events.PAYMENT_METHOD_GENERATED,function(t){o.emit(o.events.PAYMENT_METHOD_RECEIVED,t)}),e.coinbase=e.coinbase||{},e.apiClient=new i.Client({clientToken:t,integration:"coinbase"}),r.create(e)}{var i=t("braintree-api"),r=t("braintree-coinbase"),o=t("braintree-bus");t("braintree-utilities")}e.exports={initialize:n}},{"braintree-api":14,"braintree-bus":42,"braintree-coinbase":45,"braintree-utilities":299}],303:[function(t,e){"use strict";function n(t,e){return function(n){return e in t&&u.isFunction(t[e][n])?t[e][n]:function(){}}}function i(t,e){var i,d=n(e,"paypal"),f=d("onSuccess"),m=d("onCancelled"),y=new r.Client({clientToken:t,integration:"custom"});return i=o.setup(y,e),u.isFunction(e[c.ROOT_SUCCESS_CALLBACK])&&(i.onNonceReceived=function(t,n){e[c.ROOT_SUCCESS_CALLBACK](p(n))}),e.paypal&&(e.paypal.paymentMethodNonceInputField||(e.paypal.paymentMethodNonceInputField=i.paymentMethodNonceInput),e.paypal.onSuccess=function(t){i.onExternalNonceReceived(t),f.apply(null,[t.nonce,t.details.email,h(t.details.shippingAddress)])},e.paypal.onCancelled=function(){i.onExternalNonceCancelled(),m()},s.create(t,e.paypal)),e.coinbase&&(e.apiClient=y,e.paypal&&delete e.paypal,l.on(l.events.PAYMENT_METHOD_GENERATED,function(t){i.onExternalNonceReceived(t)}),a.create(e)),i}var r=t("braintree-api"),o=t("braintree-form"),s=t("braintree-paypal"),a=t("braintree-coinbase"),u=t("braintree-utilities"),c=t("../constants"),l=t("braintree-bus"),p=t("../lib/sanitize-payload"),h=t("../compatibility").convertToLegacyShippingAddress;e.exports={initialize:i}},{"../compatibility":300,"../constants":301,"../lib/sanitize-payload":307,"braintree-api":14,"braintree-bus":42,"braintree-coinbase":45,"braintree-form":205,"braintree-paypal":270,"braintree-utilities":299}],304:[function(t,e){"use strict";function n(t){return s.isFunction(t.paymentMethodNonceReceived)?t.paymentMethodNonceReceived:null}function i(t){return s.isFunction(t[u.ROOT_SUCCESS_CALLBACK])}function r(t,e){var r=n(e),s=i(e);return(r||s)&&(e.paymentMethodNonceReceived=function(t){r&&r.apply(null,[t.originalEvent,t.nonce]),delete t.originalEvent,a.emit(a.events.PAYMENT_METHOD_RECEIVED,c(t))}),o.create(t,e)}var o=t("braintree-dropin"),s=t("braintree-utilities"),a=t("braintree-bus"),u=t("../constants"),c=t("../lib/sanitize-payload");e.exports={initialize:r}},{"../constants":301,"../lib/sanitize-payload":307,"braintree-bus":42,"braintree-dropin":198,"braintree-utilities":299}],305:[function(t,e){"use strict";e.exports={custom:t("./custom"),dropin:t("./dropin"),paypal:t("./paypal"),coinbase:t("./coinbase")}},{"./coinbase":302,"./custom":303,"./dropin":304,"./paypal":306}],306:[function(t,e){"use strict";function n(t){return"onSuccess"in t&&s.isFunction(t.onSuccess)?t.onSuccess:"paypal"in t&&s.isFunction(t.paypal.onSuccess)?t.paypal.onSuccess:null}function i(t){return s.isFunction(t[a.ROOT_SUCCESS_CALLBACK])}function r(t,e){var r=n(e),s=i(e);return(r||s)&&(e.onSuccess=function(t){r&&r.apply(null,[t.nonce,t.details.email,c(t.details.shippingAddress)]),u.emit(u.events.PAYMENT_METHOD_RECEIVED,t)}),o.create(t,e)}var o=t("braintree-paypal"),s=t("braintree-utilities"),a=t("../constants"),u=t("braintree-bus"),c=t("../compatibility").convertToLegacyShippingAddress;e.exports={initialize:r}},{"../compatibility":300,"../constants":301,"braintree-bus":42,"braintree-paypal":270,"braintree-utilities":299}],307:[function(t,e){"use strict";e.exports=function(t){return{nonce:t.nonce,details:t.details,type:t.type}}},{}],308:[function(t,e){(function(n){"use strict";var i="2.6.3",r=t("braintree-rpc"),o=new r.MessageBus(n),s=new r.RPCServer(o);e.exports=function(){s.define("getExternalData",function(t){t({sdkVersion:i,merchantAppId:n.location.href})})}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"braintree-rpc":289}],309:[function(t,e){"use strict";function n(){}function i(t){if("CONFIGURATION"===t.type)throw new Error(t.message);try{console.error(t)}catch(e){console.log("ERROR: "+t.message)}}function r(t,e,n){if(!(e in p))throw new Error(e+" is an unsupported integration");return l.isFunction(n[d.ROOT_SUCCESS_CALLBACK])&&(m=function(t){n[d.ROOT_SUCCESS_CALLBACK](f(t))}),l.isFunction(n[d.ROOT_ERROR_CALLBACK])&&(y=n[d.ROOT_ERROR_CALLBACK]),n.configuration=s.parseClientToken(t),h.on(h.events.ERROR,y),h.on(h.events.PAYMENT_METHOD_RECEIVED,m),h.on(h.events.CONFIGURATION_REQUEST,function(t){t(n)}),h.on(h.events.WARNING,function(t){try{console.warn(t)}catch(e){}}),p[e].initialize(t,n)}var o="2.6.3",s=t("braintree-api"),a=t("braintree-paypal"),u=t("braintree-dropin"),c=t("braintree-form"),l=t("braintree-utilities"),p=t("./integrations"),h=t("braintree-bus"),d=t("./constants"),f=t("./lib/sanitize-payload"),m=n,y=i;e.exports={api:s,cse:Braintree,paypal:a,dropin:u,Form:c,setup:r,VERSION:o}},{"./constants":301,"./integrations":305,"./lib/sanitize-payload":307,"braintree-api":14,"braintree-bus":42,"braintree-dropin":198,"braintree-form":205,"braintree-paypal":270,"braintree-utilities":299}]},{},[1])(1)});
js/gene/braintree/vzero.js ADDED
@@ -0,0 +1,753 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /**
3
+ * Magento Braintree functionality wrapped up into a neat class
4
+ *
5
+ * @class vZero
6
+ * @author Dave Macaulay <dave@gene.co.uk>
7
+ */
8
+ var vZero = Class.create();
9
+ vZero.prototype = {
10
+
11
+ /**
12
+ * Initialize all our required variables that we'll need later on
13
+ *
14
+ * @param code The payment methods code
15
+ * @param clientToken The client token provided by the server
16
+ * @param threeDSecure Flag to determine whether 3D secure is active, this is verified server side
17
+ * @param billingName Billing name used in verification of the card
18
+ * @param billingPostcode Billing postcode also needed to verify the card
19
+ */
20
+ initialize: function (code, clientToken, threeDSecure, billingName, billingPostcode, quoteUrl, tokenizeUrl) {
21
+ this.code = code;
22
+ this.clientToken = clientToken;
23
+ this.threeDSecure = threeDSecure;
24
+
25
+ if(billingName) {
26
+ this.billingName = billingName;
27
+ }
28
+ if(billingPostcode) {
29
+ this.billingPostcode = billingPostcode;
30
+ }
31
+ if(quoteUrl) {
32
+ this.quoteUrl = quoteUrl;
33
+ }
34
+ if(tokenizeUrl) {
35
+ this.tokenizeUrl = tokenizeUrl;
36
+ }
37
+
38
+ this.acceptedCards = false;
39
+
40
+ this.closeMethod = false;
41
+ },
42
+
43
+ /**
44
+ * Init the vZero integration by starting a new version of the client
45
+ * If 3D secure is enabled we also listen out for window messages
46
+ */
47
+ init: function() {
48
+
49
+ // Different environments depending on 3D secure
50
+ if(this.threeDSecure == true) {
51
+
52
+ // Add an event in for messages
53
+ if (window.addEventListener){
54
+ window.addEventListener("message", this.receiveMessage.bind(this), false);
55
+ } else {
56
+ window.attachEvent("onmessage", this.receiveMessage.bind(this));
57
+ }
58
+ }
59
+
60
+ this.client = new braintree.api.Client({clientToken: this.clientToken});
61
+
62
+ },
63
+
64
+ /**
65
+ * Set the amount within the checkout, this is only used in the default integration
66
+ * For any other checkouts see the updateData method, this is used by 3D secure
67
+ *
68
+ * @param amount The grand total of the order
69
+ */
70
+ setAmount: function(amount) {
71
+ this.amount = parseFloat(amount);
72
+ },
73
+
74
+ /**
75
+ * We sometimes need to set the billing name later on in the process
76
+ *
77
+ * @param billingName
78
+ */
79
+ setBillingName: function(billingName) {
80
+ this.billingName = billingName;
81
+ },
82
+
83
+ /**
84
+ * Return the billing name
85
+ *
86
+ * @returns {*}
87
+ */
88
+ getBillingName: function() {
89
+
90
+ // If billingName is an object we're wanting to grab the data from elements
91
+ if(typeof this.billingName == 'object') {
92
+
93
+ // Combine them with a space
94
+ return this.combineElementsValues(this.billingName);
95
+
96
+ } else {
97
+
98
+ // Otherwise we can presume that the billing name is a string
99
+ return this.billingName;
100
+ }
101
+ },
102
+
103
+ /**
104
+ * Same for billing postcode
105
+ *
106
+ * @param billingPostcode
107
+ */
108
+ setBillingPostcode: function(billingPostcode) {
109
+ this.billingPostcode = billingPostcode;
110
+ },
111
+
112
+ /**
113
+ * Return the billing name
114
+ *
115
+ * @returns {*}
116
+ */
117
+ getBillingPostcode: function() {
118
+
119
+ // If billingName is an object we're wanting to grab the data from elements
120
+ if(typeof this.billingPostcode == 'object') {
121
+
122
+ // Combine them with a space
123
+ return this.combineElementsValues(this.billingPostcode);
124
+
125
+ } else {
126
+
127
+ // Otherwise we can presume that the billing name is a string
128
+ return this.billingPostcode;
129
+ }
130
+ },
131
+
132
+ /**
133
+ * Push through the selected accepted cards from the admin
134
+ *
135
+ * @param cards
136
+ */
137
+ setAcceptedCards: function(cards) {
138
+ this.acceptedCards = cards;
139
+ },
140
+
141
+ /**
142
+ * Return the accepted cards
143
+ *
144
+ * @returns {boolean|*}
145
+ */
146
+ getAcceptedCards: function() {
147
+ return this.acceptedCards;
148
+ },
149
+
150
+
151
+ /**
152
+ * Combine elements values into a string
153
+ *
154
+ * @param elements
155
+ * @param seperator
156
+ * @returns {string}
157
+ */
158
+ combineElementsValues: function(elements, seperator) {
159
+
160
+ // If no seperator is set use a space
161
+ if(!seperator) {
162
+ seperator = ' ';
163
+ }
164
+
165
+ // Loop through the elements and build up an array
166
+ var response = [];
167
+ elements.each(function(element, index) {
168
+ if($(element) !== undefined) {
169
+ response[index] = $(element).value;
170
+ }
171
+ });
172
+
173
+ // Join with a space
174
+ return response.join(seperator);
175
+
176
+ },
177
+
178
+ /**
179
+ * Update the card type from a card number
180
+ *
181
+ * @param cardNumber The card number that the user has entered
182
+ */
183
+ updateCardType: function(cardNumber) {
184
+
185
+ // Retrieve the card type
186
+ var cardType = vzero.getCardType(cardNumber);
187
+
188
+ if (cardType == 'card') {
189
+ // If we cannot detect which kind of card they're using remove the value from the select
190
+ $('gene_braintree_creditcard_cc_type').value = '';
191
+ } else {
192
+ // Update the validation field
193
+ $('gene_braintree_creditcard_cc_type').value = cardType;
194
+ }
195
+
196
+ // Check the image exists on the page
197
+ if($('card-type-image') != undefined) {
198
+
199
+ // Grab the skin image URL without the last part
200
+ var skinImageUrl = $('card-type-image').src.substring(0, $('card-type-image').src.lastIndexOf("/"));
201
+
202
+ // Rebuild the URL with the card type included, all card types are stored as PNG's
203
+ $('card-type-image').setAttribute('src', skinImageUrl + "/" + cardType + ".png");
204
+
205
+ }
206
+
207
+ },
208
+
209
+ /**
210
+ * Create a new event upon the card number field
211
+ */
212
+ observeCardType: function() {
213
+
214
+ if(!$$('[data-genebraintree-name="number"]').first() != undefined) {
215
+
216
+ // Observe any blurring on the form
217
+ Element.observe($$('[data-genebraintree-name="number"]').first(), 'keyup', function (event) {
218
+ vzero.updateCardType(this.value);
219
+ });
220
+
221
+ }
222
+
223
+ },
224
+
225
+ /**
226
+ * Observe all Ajax requests, this is needed on certain checkouts
227
+ * where we're unable to easily inject into methods
228
+ *
229
+ * @param callback A defined callback function if needed
230
+ */
231
+ observeAjaxRequests: function(callback) {
232
+
233
+ // For every ajax request on complete update various Braintree things
234
+ Ajax.Responders.register({
235
+ onComplete: function(transport) {
236
+
237
+ // Check the transport object has a URL and that it wasn't to our own controller
238
+ if(transport.url && transport.url.indexOf('braintree') == -1) {
239
+
240
+ // Some checkout implementations may require custom callbacks
241
+ if(callback) {
242
+ callback();
243
+ } else {
244
+ this.updateData();
245
+ }
246
+ }
247
+ }.bind(this)
248
+ });
249
+
250
+ },
251
+
252
+ /**
253
+ * Make an Ajax request to the server and request up to date information regarding the quote
254
+ *
255
+ * @param callback A defined callback function if needed
256
+ */
257
+ updateData: function(callback) {
258
+
259
+ // Make a new ajax request to the server
260
+ new Ajax.Request(
261
+ this.quoteUrl,
262
+ {
263
+ method:'post',
264
+ onSuccess: function(transport) {
265
+
266
+ // Verify we have some response text
267
+ if (transport && transport.responseText) {
268
+
269
+ // Parse as an object
270
+ try {
271
+ response = eval('(' + transport.responseText + ')');
272
+ }
273
+ catch (e) {
274
+ response = {};
275
+ }
276
+
277
+ if(response.billingName != undefined) {
278
+ this.billingName = response.billingName;
279
+ }
280
+ if(response.billingPostcode != undefined) {
281
+ this.billingPostcode = response.billingPostcode;
282
+ }
283
+ if(response.grandTotal != undefined) {
284
+ this.amount = response.grandTotal;
285
+ }
286
+
287
+ // If PayPal is active update it
288
+ if(typeof vzeroPaypal != "undefined") {
289
+
290
+ // Totals
291
+ if(response.grandTotal != undefined && response.currencyCode != undefined) {
292
+ vzeroPaypal.setPricing(response.grandTotal, response.currencyCode);
293
+ }
294
+
295
+ }
296
+
297
+ if(callback) {
298
+ callback(response);
299
+ }
300
+ }
301
+ }.bind(this)
302
+ }
303
+ );
304
+
305
+ },
306
+
307
+ /**
308
+ * Handle the user closing the 3D secure interface
309
+ *
310
+ * @param event
311
+ * @todo this functionality is not officially documented, waiting for official release of onClose method
312
+ */
313
+ receiveMessage: function(event) {
314
+
315
+ // If the user closed the window unset the load waiting
316
+ if(event.data == 'user_closed=true') {
317
+
318
+ // Is there a close method defined?
319
+ if(this.closeMethod) {
320
+ this.closeMethod();
321
+ } else {
322
+ checkout.setLoadWaiting(false);
323
+ }
324
+ }
325
+ },
326
+
327
+ /**
328
+ * Allow custom checkouts to set a custom method for closing 3D secure
329
+ *
330
+ * @param callback A defined callback function if needed
331
+ */
332
+ close3dSecureMethod: function(callback) {
333
+ this.closeMethod = callback;
334
+ },
335
+
336
+ /**
337
+ * If the user attempts to use a 3D secure vaulted card and then cancels the 3D
338
+ * window the nonce associated with that card will become invalid, due to this
339
+ * we have to tokenize all the 3D secure cards again
340
+ *
341
+ * @param callback A defined callback function if needed
342
+ */
343
+ tokenize3dSavedCards: function(callback) {
344
+
345
+ // Check 3D is enabled
346
+ if(this.threeDSecure) {
347
+
348
+ // Verify we have elements with data-token
349
+ if($$('[data-token]').first() != undefined) {
350
+
351
+ // Gather our tokens
352
+ tokens = [];
353
+ $$('[data-token]').each(function (element, index) {
354
+ tokens[index] = element.getAttribute('data-token');
355
+ });
356
+
357
+ // Make a new ajax request to the server
358
+ new Ajax.Request(
359
+ this.tokenizeUrl,
360
+ {
361
+ method:'post',
362
+ onSuccess: function(transport) {
363
+
364
+ // Verify we have some response text
365
+ if (transport && transport.responseText) {
366
+
367
+ // Parse as an object
368
+ try {
369
+ response = eval('(' + transport.responseText + ')');
370
+ }
371
+ catch (e) {
372
+ response = {};
373
+ }
374
+
375
+ // Check the response was successful
376
+ if(response.success) {
377
+
378
+ // Loop through the returned tokens
379
+ $H(response.tokens).each(function (element) {
380
+
381
+ // If the token exists update it's nonce
382
+ if($$('[data-token="' + element.key + '"]').first() != undefined) {
383
+ $$('[data-token="' + element.key + '"]').first().setAttribute('data-threedsecure-nonce', element.value);
384
+ }
385
+ });
386
+ }
387
+
388
+ if(callback) {
389
+ callback(response);
390
+ }
391
+ }
392
+ }.bind(this),
393
+ parameters: {'tokens': Object.toJSON(tokens)}
394
+ }
395
+ );
396
+ } else {
397
+ callback();
398
+ }
399
+
400
+ } else {
401
+ callback();
402
+ }
403
+ },
404
+
405
+ /**
406
+ * Make a request to Braintree for 3D secure information
407
+ *
408
+ * @param options Contains any callback functions which have been set
409
+ */
410
+ verify3dSecure: function(options) {
411
+
412
+ var threeDSecureRequest = {
413
+ amount: this.amount,
414
+ creditCard: {
415
+ number: $$('[data-genebraintree-name="number"]').first().value,
416
+ expirationMonth: $$('[data-genebraintree-name="expiration_month"]').first().value,
417
+ expirationYear: $$('[data-genebraintree-name="expiration_year"]').first().value,
418
+ cardholderName: this.getBillingName(),
419
+ billingAddress: {
420
+ postalCode: this.getBillingPostcode()
421
+ }
422
+ }
423
+ };
424
+
425
+ // If the CVV field exists include it
426
+ if($$('[data-genebraintree-name="cvv"]').first() != undefined) {
427
+ threeDSecureRequest.creditCard.cvv = $$('[data-genebraintree-name="cvv"]').first().value;
428
+ }
429
+
430
+ // Run the verify function on the braintree client
431
+ this.client.verify3DS(threeDSecureRequest, function (error, response) {
432
+
433
+ if (!error) {
434
+
435
+ // Store threeDSecure token and nonce in form
436
+ $('creditcard-payment-nonce').value = response.nonce;
437
+
438
+ // Run any callback functions
439
+ if(options.onSuccess) {
440
+ options.onSuccess();
441
+ }
442
+ } else {
443
+
444
+ // Show the error
445
+ alert(error.message);
446
+
447
+ if(options.onFailure) {
448
+ options.onFailure();
449
+ } else {
450
+ checkout.setLoadWaiting(false);
451
+ }
452
+ }
453
+ });
454
+
455
+ },
456
+
457
+ /**
458
+ * Verify a card stored in the vault
459
+ *
460
+ * @param options Contains any callback functions which have been set
461
+ */
462
+ verify3dSecureVault: function(options) {
463
+
464
+ // Get the payment nonce
465
+ var paymentNonce = $$('#creditcard-saved-accounts input:checked[type=radio]').first().getAttribute('data-threedsecure-nonce');
466
+
467
+ if(paymentNonce) {
468
+ // Run the verify function on the braintree client
469
+ this.client.verify3DS({
470
+ amount: this.amount,
471
+ creditCard: paymentNonce
472
+ }, function (error, response) {
473
+
474
+ if (!error) {
475
+
476
+ // Store threeDSecure token and nonce in form
477
+ $('creditcard-payment-nonce').removeAttribute('disabled');
478
+ $('creditcard-payment-nonce').value = response.nonce;
479
+
480
+ // Run any callback functions
481
+ if (options.onSuccess) {
482
+ options.onSuccess();
483
+ }
484
+ } else {
485
+
486
+ // Show the error
487
+ alert(error.message);
488
+
489
+ if(options.onFailure) {
490
+ options.onFailure();
491
+ } else {
492
+ checkout.setLoadWaiting(false);
493
+ }
494
+ }
495
+ });
496
+ } else {
497
+
498
+ alert('No payment nonce present.');
499
+
500
+ if(options.onFailure) {
501
+ options.onFailure();
502
+ } else {
503
+ checkout.setLoadWaiting(false);
504
+ }
505
+ }
506
+
507
+ },
508
+
509
+ /**
510
+ * Process a standard card request
511
+ *
512
+ * @param options Contains any callback functions which have been set
513
+ */
514
+ processCard: function(options) {
515
+
516
+ var tokenizeRequest = {
517
+ number: $$('[data-genebraintree-name="number"]').first().value,
518
+ cardholderName: this.getBillingName(),
519
+ expirationMonth: $$('[data-genebraintree-name="expiration_month"]').first().value,
520
+ expirationYear: $$('[data-genebraintree-name="expiration_year"]').first().value,
521
+ billingAddress: {
522
+ postalCode: this.getBillingPostcode()
523
+ }
524
+ };
525
+
526
+ // If the CVV field exists include it
527
+ if($$('[data-genebraintree-name="cvv"]').first() != undefined) {
528
+ tokenizeRequest.cvv = $$('[data-genebraintree-name="cvv"]').first().value;
529
+ }
530
+
531
+ // Attempt to tokenize the card
532
+ this.client.tokenizeCard(tokenizeRequest, function (errors, nonce) {
533
+
534
+ if(!errors) {
535
+ // Update the nonce in the form
536
+ $('creditcard-payment-nonce').value = nonce;
537
+
538
+ // Run any callback functions
539
+ if(options.onSuccess) {
540
+ options.onSuccess();
541
+ }
542
+ } else {
543
+ // Handle errors
544
+ for (var i = 0; i < errors.length; i++) {
545
+ alert(errors[i].code + " " + errors[i].message);
546
+ }
547
+
548
+ if(options.onFailure) {
549
+ options.onFailure();
550
+ } else {
551
+ checkout.setLoadWaiting(false);
552
+ }
553
+ }
554
+ });
555
+
556
+ },
557
+
558
+ /**
559
+ * Conduct a regular expression check to determine card type automatically
560
+ *
561
+ * @param number
562
+ * @returns {string}
563
+ */
564
+ getCardType: function(number) {
565
+
566
+ if (number.match(/^4/) != null)
567
+ return "VI";
568
+
569
+ if (number.match(/^(34|37)/) != null)
570
+ return "AE";
571
+
572
+ if (number.match(/^5[1-5]/) != null)
573
+ return "MC";
574
+
575
+ if (number.match(/^6011/) != null)
576
+ return "DI";
577
+
578
+ if (number.match(/^(?:2131|1800|35)/) != null)
579
+ return "JCB";
580
+
581
+ if (number.match(/^(5018|5020|5038|6304|67[0-9]{2})/) != null)
582
+ return "ME";
583
+
584
+ // Otherwise return the standard card
585
+ return "card";
586
+ },
587
+
588
+ /**
589
+ * Wrapper function which defines which method should be called
590
+ *
591
+ * verify3dSecureVault - used for verifying any vaulted card when 3D secure is enabled
592
+ * verify3dSecure - verify a normal card via 3D secure
593
+ * processCard - verify a normal card
594
+ *
595
+ * If the customer has choosen a vaulted card and 3D is disabled no client side interaction is needed
596
+ *
597
+ * @param options Object containing onSuccess, onFailure functions
598
+ */
599
+ process: function(options) {
600
+
601
+ // We have to handle vaulted 3D secure cards differently
602
+ if ($('creditcard-saved-accounts') != undefined
603
+ && $$('#creditcard-saved-accounts input:checked[type=radio]').first() != undefined
604
+ && $$('#creditcard-saved-accounts input:checked[type=radio]').first().hasAttribute('data-threedsecure-nonce'))
605
+ {
606
+ // The user has selected a card stored via 3D secure
607
+ this.verify3dSecureVault(options);
608
+
609
+ } else if($('creditcard-saved-accounts') != undefined
610
+ && $$('#creditcard-saved-accounts input:checked[type=radio]').first() != undefined
611
+ && $$('#creditcard-saved-accounts input:checked[type=radio]').first().value !== 'other')
612
+ {
613
+ // No action required as we're using a saved card
614
+ if(options.onSuccess) {
615
+ options.onSuccess()
616
+ }
617
+
618
+ } else if(this.threeDSecure == true) {
619
+
620
+ // Standard 3D secure callback
621
+ this.verify3dSecure(options);
622
+
623
+ } else {
624
+
625
+ // Otherwise process the card normally
626
+ this.processCard(options);
627
+ }
628
+ }
629
+
630
+ };
631
+
632
+ /**
633
+ * Separate class to handle functionality around the vZero PayPal button
634
+ *
635
+ * @class vZeroPayPalButton
636
+ * @author Dave Macaulay <dave@gene.co.uk>
637
+ */
638
+ var vZeroPayPalButton = Class.create();
639
+ vZeroPayPalButton.prototype = {
640
+
641
+ /**
642
+ * Initialize the PayPal button class
643
+ *
644
+ * @param clientToken Client token generated from server
645
+ * @param storeFrontName The store name to show within the PayPal modal window
646
+ * @param singleUse Should the system attempt to open in single payment mode?
647
+ * @param locale The locale for the pamynet
648
+ * @param futureSingleUse When using future payments should we process the transaction as a single payment?
649
+ */
650
+ initialize: function (clientToken, storeFrontName, singleUse, locale, futureSingleUse) {
651
+ this.clientToken = clientToken;
652
+ this.storeFrontName = storeFrontName;
653
+ this.singleUse = singleUse;
654
+ this.locale = locale;
655
+ this.futureSingleUse = futureSingleUse;
656
+
657
+ this.PayPalClient = false;
658
+ },
659
+
660
+ /**
661
+ * Update the pricing information for the PayPal button
662
+ * If the PayPalClient has already been created we also update the _clientOptions
663
+ * so the PayPal modal window displays the correct values
664
+ *
665
+ * @param amount The amount formatted to two decimal places
666
+ * @param currency The currency code
667
+ */
668
+ setPricing: function(amount, currency) {
669
+
670
+ // Set them into the class
671
+ this.amount = parseFloat(amount);
672
+ this.currency = currency;
673
+
674
+ // If the client exists update the clientOptions
675
+ if(this.PayPalClient._clientOptions != undefined) {
676
+ this.PayPalClient._clientOptions.amount = parseFloat(amount);
677
+ this.PayPalClient._clientOptions.currency = currency;
678
+ }
679
+ },
680
+
681
+ /**
682
+ * Inject the PayPal button into the document
683
+ *
684
+ * @param options Object containing onSuccess method
685
+ */
686
+ addPayPalButton: function(options) {
687
+
688
+ // Build up our setup configuration
689
+ var setupConfiguration = {
690
+ container: "paypal-container",
691
+ paymentMethodNonceInputField: "paypal-payment-nonce",
692
+ displayName: this.storeFrontName,
693
+ onPaymentMethodReceived: function(obj) {
694
+
695
+ // If a callback is defined we're doing something crazy!
696
+ if(typeof options != 'undefined' && options.onSuccess) {
697
+ options.onSuccess(obj);
698
+ } else {
699
+ // Force check
700
+ payment.switchMethod('gene_braintree_paypal');
701
+
702
+ // Re-enable the form
703
+ $('paypal-payment-nonce').disabled = false;
704
+
705
+ // Remove the PayPal button
706
+ $('paypal-complete').remove();
707
+
708
+ // Submit the checkout steps
709
+ review.save();
710
+ }
711
+
712
+ },
713
+ onUnsupported: function() {
714
+ alert('Sadly your browser does not support purchasing with PayPal.');
715
+ }
716
+ };
717
+
718
+ // Detect single use
719
+ if(this.singleUse == true) {
720
+
721
+ setupConfiguration.singleUse = true;
722
+ setupConfiguration.amount = this.amount;
723
+ setupConfiguration.currency = this.currency;
724
+ setupConfiguration.locale = this.locale;
725
+
726
+ } else if(this.futureSingleUse == true) {
727
+
728
+ setupConfiguration.singleUse = true;
729
+
730
+ }
731
+
732
+ // Start a new version of the client and assign for later modifications
733
+ this.PayPalClient = braintree.setup(this.clientToken, "paypal", setupConfiguration);
734
+ },
735
+
736
+ /**
737
+ * Allow closing of the PayPal window
738
+ *
739
+ * @param callback A defined callback function if needed
740
+ */
741
+ closePayPalWindow: function(callback) {
742
+
743
+ // Make sure the client is active
744
+ if(this.PayPalClient != undefined) {
745
+ this.PayPalClient._close();
746
+
747
+ if(callback) {
748
+ callback();
749
+ }
750
+ }
751
+ }
752
+
753
+ };
lib/Braintree.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PHP Library
4
+ *
5
+ * Braintree base class and initialization
6
+ * Provides methods to child classes. This class cannot be instantiated.
7
+ *
8
+ * PHP version 5
9
+ *
10
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
11
+ */
12
+
13
+
14
+ set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__)));
15
+
16
+ abstract class Braintree
17
+ {
18
+ /**
19
+ * @ignore
20
+ * don't permit an explicit call of the constructor!
21
+ * (like $t = new Braintree_Transaction())
22
+ */
23
+ protected function __construct()
24
+ {
25
+ }
26
+ /**
27
+ * @ignore
28
+ * don't permit cloning the instances (like $x = clone $v)
29
+ */
30
+ protected function __clone()
31
+ {
32
+ }
33
+
34
+ /**
35
+ * returns private/nonexistent instance properties
36
+ * @ignore
37
+ * @access public
38
+ * @param string $name property name
39
+ * @return mixed contents of instance properties
40
+ */
41
+ public function __get($name)
42
+ {
43
+ if (array_key_exists($name, $this->_attributes)) {
44
+ return $this->_attributes[$name];
45
+ }
46
+ else {
47
+ trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE);
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * used by isset() and empty()
54
+ * @access public
55
+ * @param string $name property name
56
+ * @return boolean
57
+ */
58
+ public function __isset($name)
59
+ {
60
+ return array_key_exists($name, $this->_attributes);
61
+ }
62
+
63
+ public function _set($key, $value)
64
+ {
65
+ $this->_attributes[$key] = $value;
66
+ }
67
+ }
68
+ require_once('Braintree/Modification.php');
69
+ require_once('Braintree/Instance.php');
70
+
71
+ require_once('Braintree/Address.php');
72
+ require_once('Braintree/AddressGateway.php');
73
+ require_once('Braintree/AddOn.php');
74
+ require_once('Braintree/AddOnGateway.php');
75
+ require_once('Braintree/ApplePayCard.php');
76
+ require_once('Braintree/ClientToken.php');
77
+ require_once('Braintree/ClientTokenGateway.php');
78
+ require_once('Braintree/CoinbaseAccount.php');
79
+ require_once('Braintree/Collection.php');
80
+ require_once('Braintree/Configuration.php');
81
+ require_once('Braintree/CreditCard.php');
82
+ require_once('Braintree/CreditCardGateway.php');
83
+ require_once('Braintree/Customer.php');
84
+ require_once('Braintree/CustomerGateway.php');
85
+ require_once('Braintree/CustomerSearch.php');
86
+ require_once('Braintree/DisbursementDetails.php');
87
+ require_once('Braintree/Dispute.php');
88
+ require_once('Braintree/Dispute/TransactionDetails.php');
89
+ require_once('Braintree/Descriptor.php');
90
+ require_once('Braintree/Digest.php');
91
+ require_once('Braintree/Discount.php');
92
+ require_once('Braintree/DiscountGateway.php');
93
+ require_once('Braintree/IsNode.php');
94
+ require_once('Braintree/EqualityNode.php');
95
+ require_once('Braintree/Exception.php');
96
+ require_once('Braintree/Gateway.php');
97
+ require_once('Braintree/Http.php');
98
+ require_once('Braintree/KeyValueNode.php');
99
+ require_once('Braintree/MerchantAccount.php');
100
+ require_once('Braintree/MerchantAccountGateway.php');
101
+ require_once('Braintree/MerchantAccount/BusinessDetails.php');
102
+ require_once('Braintree/MerchantAccount/FundingDetails.php');
103
+ require_once('Braintree/MerchantAccount/IndividualDetails.php');
104
+ require_once('Braintree/MerchantAccount/AddressDetails.php');
105
+ require_once('Braintree/MultipleValueNode.php');
106
+ require_once('Braintree/MultipleValueOrTextNode.php');
107
+ require_once('Braintree/PartialMatchNode.php');
108
+ require_once('Braintree/Plan.php');
109
+ require_once('Braintree/PlanGateway.php');
110
+ require_once('Braintree/RangeNode.php');
111
+ require_once('Braintree/ResourceCollection.php');
112
+ require_once('Braintree/RiskData.php');
113
+ require_once('Braintree/SettlementBatchSummary.php');
114
+ require_once('Braintree/SettlementBatchSummaryGateway.php');
115
+ require_once('Braintree/SignatureService.php');
116
+ require_once('Braintree/Subscription.php');
117
+ require_once('Braintree/SubscriptionGateway.php');
118
+ require_once('Braintree/SubscriptionSearch.php');
119
+ require_once('Braintree/Subscription/StatusDetails.php');
120
+ require_once('Braintree/TextNode.php');
121
+ require_once('Braintree/Transaction.php');
122
+ require_once('Braintree/TransactionGateway.php');
123
+ require_once('Braintree/Disbursement.php');
124
+ require_once('Braintree/TransactionSearch.php');
125
+ require_once('Braintree/TransparentRedirect.php');
126
+ require_once('Braintree/TransparentRedirectGateway.php');
127
+ require_once('Braintree/Util.php');
128
+ require_once('Braintree/Version.php');
129
+ require_once('Braintree/Xml.php');
130
+ require_once('Braintree/Error/Codes.php');
131
+ require_once('Braintree/Error/ErrorCollection.php');
132
+ require_once('Braintree/Error/Validation.php');
133
+ require_once('Braintree/Error/ValidationErrorCollection.php');
134
+ require_once('Braintree/Exception/Authentication.php');
135
+ require_once('Braintree/Exception/Authorization.php');
136
+ require_once('Braintree/Exception/Configuration.php');
137
+ require_once('Braintree/Exception/DownForMaintenance.php');
138
+ require_once('Braintree/Exception/ForgedQueryString.php');
139
+ require_once('Braintree/Exception/InvalidSignature.php');
140
+ require_once('Braintree/Exception/NotFound.php');
141
+ require_once('Braintree/Exception/ServerError.php');
142
+ require_once('Braintree/Exception/SSLCertificate.php');
143
+ require_once('Braintree/Exception/SSLCaFileNotFound.php');
144
+ require_once('Braintree/Exception/Unexpected.php');
145
+ require_once('Braintree/Exception/UpgradeRequired.php');
146
+ require_once('Braintree/Exception/ValidationsFailed.php');
147
+ require_once('Braintree/Result/CreditCardVerification.php');
148
+ require_once('Braintree/Result/Error.php');
149
+ require_once('Braintree/Result/Successful.php');
150
+ require_once('Braintree/Test/CreditCardNumbers.php');
151
+ require_once('Braintree/Test/MerchantAccount.php');
152
+ require_once('Braintree/Test/TransactionAmounts.php');
153
+ require_once('Braintree/Test/VenmoSdk.php');
154
+ require_once('Braintree/Test/Nonces.php');
155
+ require_once('Braintree/Transaction/AddressDetails.php');
156
+ require_once('Braintree/Transaction/ApplePayCardDetails.php');
157
+ require_once('Braintree/Transaction/CoinbaseDetails.php');
158
+ require_once('Braintree/Transaction/CreditCardDetails.php');
159
+ require_once('Braintree/Transaction/PayPalDetails.php');
160
+ require_once('Braintree/Transaction/CustomerDetails.php');
161
+ require_once('Braintree/Transaction/StatusDetails.php');
162
+ require_once('Braintree/Transaction/SubscriptionDetails.php');
163
+ require_once('Braintree/WebhookNotification.php');
164
+ require_once('Braintree/WebhookTesting.php');
165
+ require_once('Braintree/Xml/Generator.php');
166
+ require_once('Braintree/Xml/Parser.php');
167
+ require_once('Braintree/CreditCardVerification.php');
168
+ require_once('Braintree/CreditCardVerificationGateway.php');
169
+ require_once('Braintree/CreditCardVerificationSearch.php');
170
+ require_once('Braintree/PartnerMerchant.php');
171
+ require_once('Braintree/PayPalAccount.php');
172
+ require_once('Braintree/PayPalAccountGateway.php');
173
+ require_once('Braintree/PaymentMethod.php');
174
+ require_once('Braintree/PaymentMethodGateway.php');
175
+ require_once('Braintree/PaymentMethodNonce.php');
176
+ require_once('Braintree/PaymentMethodNonceGateway.php');
177
+ require_once('Braintree/PaymentInstrumentType.php');
178
+ require_once('Braintree/UnknownPaymentMethod.php');
179
+
180
+ if (version_compare(PHP_VERSION, '5.2.1', '<')) {
181
+ throw new Braintree_Exception('PHP version >= 5.2.1 required');
182
+ }
183
+
184
+
185
+ function requireDependencies() {
186
+ $requiredExtensions = array('xmlwriter', 'SimpleXML', 'openssl', 'dom', 'hash', 'curl');
187
+ foreach ($requiredExtensions AS $ext) {
188
+ if (!extension_loaded($ext)) {
189
+ throw new Braintree_Exception('The Braintree library requires the ' . $ext . ' extension.');
190
+ }
191
+ }
192
+ }
193
+
194
+ requireDependencies();
lib/Braintree/AddOn.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_AddOn extends Braintree_Modification
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self();
7
+ $instance->_initialize($attributes);
8
+ return $instance;
9
+ }
10
+
11
+
12
+ // static methods redirecting to gateway
13
+
14
+ public static function all()
15
+ {
16
+ return Braintree_Configuration::gateway()->addOn()->all();
17
+ }
18
+ }
lib/Braintree/AddOnGateway.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_AddOnGateway
3
+ {
4
+ private $_gateway;
5
+ private $_config;
6
+ private $_http;
7
+
8
+ public function __construct($gateway)
9
+ {
10
+ $this->_gateway = $gateway;
11
+ $this->_config = $gateway->config;
12
+ $this->_http = new Braintree_Http($gateway->config);
13
+ }
14
+
15
+ public function all()
16
+ {
17
+ $path = $this->_config->merchantPath() . '/add_ons';
18
+ $response = $this->_http->get($path);
19
+
20
+ $addOns = array("addOn" => $response['addOns']);
21
+
22
+ return Braintree_Util::extractAttributeAsArray(
23
+ $addOns,
24
+ 'addOn'
25
+ );
26
+ }
27
+ }
lib/Braintree/Address.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Address module
4
+ * PHP Version 5
5
+ * Creates and manages Braintree Addresses
6
+ *
7
+ * An Address belongs to a Customer. It can be associated to a
8
+ * CreditCard as the billing address. It can also be used
9
+ * as the shipping address when creating a Transaction.
10
+ *
11
+ * @package Braintree
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ *
14
+ * @property-read string $company
15
+ * @property-read string $countryName
16
+ * @property-read string $createdAt
17
+ * @property-read string $customerId
18
+ * @property-read string $extendedAddress
19
+ * @property-read string $firstName
20
+ * @property-read string $id
21
+ * @property-read string $lastName
22
+ * @property-read string $locality
23
+ * @property-read string $postalCode
24
+ * @property-read string $region
25
+ * @property-read string $streetAddress
26
+ * @property-read string $updatedAt
27
+ */
28
+ class Braintree_Address extends Braintree
29
+ {
30
+ /**
31
+ * returns false if comparing object is not a Braintree_Address,
32
+ * or is a Braintree_Address with a different id
33
+ *
34
+ * @param object $other address to compare against
35
+ * @return boolean
36
+ */
37
+ public function isEqual($other)
38
+ {
39
+ return !($other instanceof Braintree_Address) ?
40
+ false :
41
+ ($this->id === $other->id && $this->customerId === $other->customerId);
42
+ }
43
+
44
+ /**
45
+ * create a printable representation of the object as:
46
+ * ClassName[property=value, property=value]
47
+ * @ignore
48
+ * @return var
49
+ */
50
+ public function __toString()
51
+ {
52
+ return __CLASS__ . '[' .
53
+ Braintree_Util::attributesToString($this->_attributes) .']';
54
+ }
55
+
56
+ /**
57
+ * sets instance properties from an array of values
58
+ *
59
+ * @ignore
60
+ * @access protected
61
+ * @param array $addressAttribs array of address data
62
+ * @return none
63
+ */
64
+ protected function _initialize($addressAttribs)
65
+ {
66
+ // set the attributes
67
+ $this->_attributes = $addressAttribs;
68
+ }
69
+
70
+ /**
71
+ * factory method: returns an instance of Braintree_Address
72
+ * to the requesting method, with populated properties
73
+ * @ignore
74
+ * @return object instance of Braintree_Address
75
+ */
76
+ public static function factory($attributes)
77
+ {
78
+ $instance = new self();
79
+ $instance->_initialize($attributes);
80
+ return $instance;
81
+
82
+ }
83
+
84
+
85
+ // static methods redirecting to gateway
86
+
87
+ public static function create($attribs)
88
+ {
89
+ return Braintree_Configuration::gateway()->address()->create($attribs);
90
+ }
91
+
92
+ public static function createNoValidate($attribs)
93
+ {
94
+ return Braintree_Configuration::gateway()->address()->createNoValidate($attribs);
95
+ }
96
+
97
+ public static function delete($customerOrId = null, $addressId = null)
98
+ {
99
+ return Braintree_Configuration::gateway()->address()->delete($customerOrId, $addressId);
100
+ }
101
+
102
+ public static function find($customerOrId, $addressId)
103
+ {
104
+ return Braintree_Configuration::gateway()->address()->find($customerOrId, $addressId);
105
+ }
106
+
107
+ public static function update($customerOrId, $addressId, $attributes)
108
+ {
109
+ return Braintree_Configuration::gateway()->address()->update($customerOrId, $addressId, $attributes);
110
+ }
111
+
112
+ public static function updateNoValidate($customerOrId, $addressId, $attributes)
113
+ {
114
+ return Braintree_Configuration::gateway()->address()->updateNoValidate($customerOrId, $addressId, $attributes);
115
+ }
116
+ }
lib/Braintree/AddressGateway.php ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree AddressGateway module
4
+ * PHP Version 5
5
+ * Creates and manages Braintree Addresses
6
+ *
7
+ * An Address belongs to a Customer. It can be associated to a
8
+ * CreditCard as the billing address. It can also be used
9
+ * as the shipping address when creating a Transaction.
10
+ *
11
+ * @package Braintree
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_AddressGateway
15
+ {
16
+ private $_gateway;
17
+ private $_config;
18
+ private $_http;
19
+
20
+ public function __construct($gateway)
21
+ {
22
+ $this->_gateway = $gateway;
23
+ $this->_config = $gateway->config;
24
+ $this->_http = new Braintree_Http($gateway->config);
25
+ }
26
+
27
+
28
+ /* public class methods */
29
+ /**
30
+ *
31
+ * @access public
32
+ * @param array $attribs
33
+ * @return object Result, either Successful or Error
34
+ */
35
+ public function create($attribs)
36
+ {
37
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
38
+ $customerId = isset($attribs['customerId']) ?
39
+ $attribs['customerId'] :
40
+ null;
41
+
42
+ $this->_validateCustomerId($customerId);
43
+ unset($attribs['customerId']);
44
+ return $this->_doCreate(
45
+ '/customers/' . $customerId . '/addresses',
46
+ array('address' => $attribs)
47
+ );
48
+ }
49
+
50
+ /**
51
+ * attempts the create operation assuming all data will validate
52
+ * returns a Braintree_Address object instead of a Result
53
+ *
54
+ * @access public
55
+ * @param array $attribs
56
+ * @return object
57
+ * @throws Braintree_Exception_ValidationError
58
+ */
59
+ public function createNoValidate($attribs)
60
+ {
61
+ $result = $this->create($attribs);
62
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
63
+
64
+ }
65
+
66
+ /**
67
+ * delete an address by id
68
+ *
69
+ * @param mixed $customerOrId
70
+ * @param string $addressId
71
+ */
72
+ public function delete($customerOrId = null, $addressId = null)
73
+ {
74
+ $this->_validateId($addressId);
75
+ $customerId = $this->_determineCustomerId($customerOrId);
76
+ $path = $this->_config->merchantPath() . '/customers/' . $customerId . '/addresses/' . $addressId;
77
+ $this->_http->delete($path);
78
+ return new Braintree_Result_Successful();
79
+ }
80
+
81
+ /**
82
+ * find an address by id
83
+ *
84
+ * Finds the address with the given <b>addressId</b> that is associated
85
+ * to the given <b>customerOrId</b>.
86
+ * If the address cannot be found, a NotFound exception will be thrown.
87
+ *
88
+ *
89
+ * @access public
90
+ * @param mixed $customerOrId
91
+ * @param string $addressId
92
+ * @return object Braintree_Address
93
+ * @throws Braintree_Exception_NotFound
94
+ */
95
+ public function find($customerOrId, $addressId)
96
+ {
97
+
98
+ $customerId = $this->_determineCustomerId($customerOrId);
99
+ $this->_validateId($addressId);
100
+
101
+ try {
102
+ $path = $this->_config->merchantPath() . '/customers/' . $customerId . '/addresses/' . $addressId;
103
+ $response = $this->_http->get($path);
104
+ return Braintree_Address::factory($response['address']);
105
+ } catch (Braintree_Exception_NotFound $e) {
106
+ throw new Braintree_Exception_NotFound(
107
+ 'address for customer ' . $customerId .
108
+ ' with id ' . $addressId . ' not found.'
109
+ );
110
+ }
111
+
112
+ }
113
+
114
+ /**
115
+ * updates the address record
116
+ *
117
+ * if calling this method in context,
118
+ * customerOrId is the 2nd attribute, addressId 3rd.
119
+ * customerOrId & addressId are not sent in object context.
120
+ *
121
+ *
122
+ * @access public
123
+ * @param array $attributes
124
+ * @param mixed $customerOrId (only used in call)
125
+ * @param string $addressId (only used in call)
126
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
127
+ */
128
+ public function update($customerOrId, $addressId, $attributes)
129
+ {
130
+ $this->_validateId($addressId);
131
+ $customerId = $this->_determineCustomerId($customerOrId);
132
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
133
+
134
+ $path = $this->_config->merchantPath() . '/customers/' . $customerId . '/addresses/' . $addressId;
135
+ $response = $this->_http->put($path, array('address' => $attributes));
136
+
137
+ return $this->_verifyGatewayResponse($response);
138
+
139
+ }
140
+
141
+ /**
142
+ * update an address record, assuming validations will pass
143
+ *
144
+ * if calling this method in context,
145
+ * customerOrId is the 2nd attribute, addressId 3rd.
146
+ * customerOrId & addressId are not sent in object context.
147
+ *
148
+ * @access public
149
+ * @param array $transactionAttribs
150
+ * @param string $customerId
151
+ * @return object Braintree_Transaction
152
+ * @throws Braintree_Exception_ValidationsFailed
153
+ * @see Braintree_Address::update()
154
+ */
155
+ public function updateNoValidate($customerOrId, $addressId, $attributes)
156
+ {
157
+ $result = $this->update($customerOrId, $addressId, $attributes);
158
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
159
+ }
160
+
161
+ /**
162
+ * creates a full array signature of a valid create request
163
+ * @return array gateway create request format
164
+ */
165
+ public static function createSignature()
166
+ {
167
+ return array(
168
+ 'company', 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
169
+ 'countryName', 'customerId', 'extendedAddress', 'firstName',
170
+ 'lastName', 'locality', 'postalCode', 'region', 'streetAddress'
171
+ );
172
+ }
173
+
174
+ /**
175
+ * creates a full array signature of a valid update request
176
+ * @return array gateway update request format
177
+ */
178
+ public static function updateSignature()
179
+ {
180
+ // TODO: remove customerId from update signature
181
+ return self::createSignature();
182
+
183
+ }
184
+
185
+ /**
186
+ * verifies that a valid address id is being used
187
+ * @ignore
188
+ * @param string $id address id
189
+ * @throws InvalidArgumentException
190
+ */
191
+ private function _validateId($id = null)
192
+ {
193
+ if (empty($id) || trim($id) == "") {
194
+ throw new InvalidArgumentException(
195
+ 'expected address id to be set'
196
+ );
197
+ }
198
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
199
+ throw new InvalidArgumentException(
200
+ $id . ' is an invalid address id.'
201
+ );
202
+ }
203
+ }
204
+
205
+ /**
206
+ * verifies that a valid customer id is being used
207
+ * @ignore
208
+ * @param string $id customer id
209
+ * @throws InvalidArgumentException
210
+ */
211
+ private function _validateCustomerId($id = null)
212
+ {
213
+ if (empty($id) || trim($id) == "") {
214
+ throw new InvalidArgumentException(
215
+ 'expected customer id to be set'
216
+ );
217
+ }
218
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
219
+ throw new InvalidArgumentException(
220
+ $id . ' is an invalid customer id.'
221
+ );
222
+ }
223
+
224
+ }
225
+
226
+ /**
227
+ * determines if a string id or Customer object was passed
228
+ * @ignore
229
+ * @param mixed $customerOrId
230
+ * @return string customerId
231
+ */
232
+ private function _determineCustomerId($customerOrId)
233
+ {
234
+ $customerId = ($customerOrId instanceof Braintree_Customer) ? $customerOrId->id : $customerOrId;
235
+ $this->_validateCustomerId($customerId);
236
+ return $customerId;
237
+
238
+ }
239
+
240
+ /* private class methods */
241
+ /**
242
+ * sends the create request to the gateway
243
+ * @ignore
244
+ * @param string $subPath
245
+ * @param array $params
246
+ * @return mixed
247
+ */
248
+ private function _doCreate($subPath, $params)
249
+ {
250
+ $fullPath = $this->_config->merchantPath() . $subPath;
251
+ $response = $this->_http->post($fullPath, $params);
252
+
253
+ return $this->_verifyGatewayResponse($response);
254
+
255
+ }
256
+
257
+ /**
258
+ * generic method for validating incoming gateway responses
259
+ *
260
+ * creates a new Braintree_Address object and encapsulates
261
+ * it inside a Braintree_Result_Successful object, or
262
+ * encapsulates a Braintree_Errors object inside a Result_Error
263
+ * alternatively, throws an Unexpected exception if the response is invalid.
264
+ *
265
+ * @ignore
266
+ * @param array $response gateway response values
267
+ * @return object Result_Successful or Result_Error
268
+ * @throws Braintree_Exception_Unexpected
269
+ */
270
+ private function _verifyGatewayResponse($response)
271
+ {
272
+ if (isset($response['address'])) {
273
+ // return a populated instance of Braintree_Address
274
+ return new Braintree_Result_Successful(
275
+ Braintree_Address::factory($response['address'])
276
+ );
277
+ } else if (isset($response['apiErrorResponse'])) {
278
+ return new Braintree_Result_Error($response['apiErrorResponse']);
279
+ } else {
280
+ throw new Braintree_Exception_Unexpected(
281
+ "Expected address or apiErrorResponse"
282
+ );
283
+ }
284
+
285
+ }
286
+ }
lib/Braintree/ApplePayCard.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree ApplePayCard module
4
+ * Creates and manages Braintree Apple Pay cards
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * See {@link https://developers.braintreepayments.com/javascript+php}<br />
9
+ *
10
+ * @package Braintree
11
+ * @category Resources
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ *
14
+ * @property-read string $cardType
15
+ * @property-read string $createdAt
16
+ * @property-read string $expirationDate
17
+ * @property-read string $expirationMonth
18
+ * @property-read string $expirationYear
19
+ * @property-read string $imageUrl
20
+ * @property-read string $last4
21
+ * @property-read string $token
22
+ * @property-read string $paymentInstrumentName
23
+ * @property-read string $updatedAt
24
+ */
25
+ class Braintree_ApplePayCard extends Braintree
26
+ {
27
+ // Card Type
28
+ const AMEX = 'Apple Pay - American Express';
29
+ const MASTER_CARD = 'Apple Pay - MasterCard';
30
+ const VISA = 'Apple Pay - Visa';
31
+
32
+ /* instance methods */
33
+ /**
34
+ * returns false if default is null or false
35
+ *
36
+ * @return boolean
37
+ */
38
+ public function isDefault()
39
+ {
40
+ return $this->default;
41
+ }
42
+
43
+ /**
44
+ * checks whether the card is expired based on the current date
45
+ *
46
+ * @return boolean
47
+ */
48
+ public function isExpired()
49
+ {
50
+ return $this->expired;
51
+ }
52
+
53
+ /**
54
+ * factory method: returns an instance of Braintree_ApplePayCard
55
+ * to the requesting method, with populated properties
56
+ *
57
+ * @ignore
58
+ * @return object instance of Braintree_ApplePayCard
59
+ */
60
+ public static function factory($attributes)
61
+ {
62
+ $defaultAttributes = array(
63
+ 'expirationMonth' => '',
64
+ 'expirationYear' => '',
65
+ 'last4' => '',
66
+ );
67
+
68
+ $instance = new self();
69
+ $instance->_initialize(array_merge($defaultAttributes, $attributes));
70
+ return $instance;
71
+ }
72
+
73
+ /**
74
+ * sets instance properties from an array of values
75
+ *
76
+ * @access protected
77
+ * @param array $applePayCardAttribs array of Apple Pay card properties
78
+ * @return none
79
+ */
80
+ protected function _initialize($applePayCardAttribs)
81
+ {
82
+ // set the attributes
83
+ $this->_attributes = $applePayCardAttribs;
84
+
85
+ $subscriptionArray = array();
86
+ if (isset($applePayCardAttribs['subscriptions'])) {
87
+ foreach ($applePayCardAttribs['subscriptions'] AS $subscription) {
88
+ $subscriptionArray[] = Braintree_Subscription::factory($subscription);
89
+ }
90
+ }
91
+
92
+ $this->_set('subscriptions', $subscriptionArray);
93
+ $this->_set('expirationDate', $this->expirationMonth . '/' . $this->expirationYear);
94
+ }
95
+ }
lib/Braintree/ClientToken.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_ClientToken
4
+ {
5
+ const DEFAULT_VERSION = 2;
6
+
7
+
8
+ // static methods redirecting to gateway
9
+
10
+ public static function generate($params=array())
11
+ {
12
+ return Braintree_Configuration::gateway()->clientToken()->generate($params);
13
+ }
14
+
15
+ public static function conditionallyVerifyKeys($params)
16
+ {
17
+ return Braintree_Configuration::gateway()->clientToken()->conditionallyVerifyKeys($params);
18
+ }
19
+
20
+ public static function generateWithCustomerIdSignature()
21
+ {
22
+ return Braintree_Configuration::gateway()->clientToken()->generateWithCustomerIdSignature();
23
+ }
24
+
25
+ public static function generateWithoutCustomerIdSignature()
26
+ {
27
+ return Braintree_Configuration::gateway()->clientToken()->generateWithoutCustomerIdSignature();
28
+ }
29
+ }
lib/Braintree/ClientTokenGateway.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_ClientTokenGateway
4
+ {
5
+ private $_gateway;
6
+ private $_config;
7
+ private $_http;
8
+
9
+ public function __construct($gateway)
10
+ {
11
+ $this->_gateway = $gateway;
12
+ $this->_config = $gateway->config;
13
+ $this->_http = new Braintree_Http($gateway->config);
14
+ }
15
+
16
+ public function generate($params=array())
17
+ {
18
+ if (!array_key_exists("version", $params)) {
19
+ $params["version"] = Braintree_ClientToken::DEFAULT_VERSION;
20
+ }
21
+
22
+ $this->conditionallyVerifyKeys($params);
23
+ $generateParams = array("client_token" => $params);
24
+
25
+ return $this->_doGenerate('/client_token', $generateParams);
26
+ }
27
+
28
+ /**
29
+ * sends the generate request to the gateway
30
+ *
31
+ * @ignore
32
+ * @param var $url
33
+ * @param array $params
34
+ * @return mixed
35
+ */
36
+ public function _doGenerate($subPath, $params)
37
+ {
38
+ $fullPath = $this->_config->merchantPath() . $subPath;
39
+ $response = $this->_http->post($fullPath, $params);
40
+
41
+ return $this->_verifyGatewayResponse($response);
42
+ }
43
+
44
+ public function conditionallyVerifyKeys($params)
45
+ {
46
+ if (array_key_exists("customerId", $params)) {
47
+ Braintree_Util::verifyKeys($this->generateWithCustomerIdSignature(), $params);
48
+ } else {
49
+ Braintree_Util::verifyKeys($this->generateWithoutCustomerIdSignature(), $params);
50
+ }
51
+ }
52
+
53
+ public function generateWithCustomerIdSignature()
54
+ {
55
+ return array("version", "customerId", "proxyMerchantId", array("options" => array("makeDefault", "verifyCard", "failOnDuplicatePaymentMethod")), "merchantAccountId");
56
+ }
57
+
58
+ public function generateWithoutCustomerIdSignature()
59
+ {
60
+ return array("version", "proxyMerchantId", "merchantAccountId");
61
+ }
62
+
63
+ /**
64
+ * generic method for validating incoming gateway responses
65
+ *
66
+ * If the request is successful, returns a client token string.
67
+ * Otherwise, throws an InvalidArgumentException with the error
68
+ * response from the Gateway or an HTTP status code exception.
69
+ *
70
+ * @ignore
71
+ * @param array $response gateway response values
72
+ * @return string client token
73
+ * @throws InvalidArgumentException | HTTP status code exception
74
+ */
75
+ private function _verifyGatewayResponse($response)
76
+ {
77
+ if (isset($response['clientToken'])) {
78
+ return $response['clientToken']['value'];
79
+ } elseif (isset($response['apiErrorResponse'])) {
80
+ throw new InvalidArgumentException(
81
+ $response['apiErrorResponse']['message']
82
+ );
83
+ } else {
84
+ throw new Braintree_Exception_Unexpected(
85
+ "Expected clientToken or apiErrorResponse"
86
+ );
87
+ }
88
+ }
89
+
90
+ }
lib/Braintree/CoinbaseAccount.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree CoinbaseAccount module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Manages Braintree CoinbaseAccounts
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ * @property-read string $token
21
+ * @property-read string $userId
22
+ * @property-read string $userName
23
+ * @property-read string $userEmail
24
+ */
25
+ class Braintree_CoinbaseAccount extends Braintree
26
+ {
27
+ /**
28
+ * factory method: returns an instance of Braintree_CoinbaseAccount
29
+ * to the requesting method, with populated properties
30
+ *
31
+ * @ignore
32
+ * @return object instance of Braintree_CoinbaseAccount
33
+ */
34
+ public static function factory($attributes)
35
+ {
36
+ $instance = new self();
37
+ $instance->_initialize($attributes);
38
+ return $instance;
39
+ }
40
+
41
+ /* instance methods */
42
+
43
+ /**
44
+ * returns false if default is null or false
45
+ *
46
+ * @return boolean
47
+ */
48
+ public function isDefault()
49
+ {
50
+ return $this->default;
51
+ }
52
+
53
+ /**
54
+ * sets instance properties from an array of values
55
+ *
56
+ * @access protected
57
+ * @param array $coinbaseAccountAttribs array of coinbaseAccount data
58
+ * @return none
59
+ */
60
+ protected function _initialize($coinbaseAccountAttribs)
61
+ {
62
+ // set the attributes
63
+ $this->_attributes = $coinbaseAccountAttribs;
64
+
65
+ $subscriptionArray = array();
66
+ if (isset($coinbaseAccountAttribs['subscriptions'])) {
67
+ foreach ($coinbaseAccountAttribs['subscriptions'] AS $subscription) {
68
+ $subscriptionArray[] = Braintree_Subscription::factory($subscription);
69
+ }
70
+ }
71
+
72
+ $this->_set('subscriptions', $subscriptionArray);
73
+ }
74
+
75
+ /**
76
+ * create a printable representation of the object as:
77
+ * ClassName[property=value, property=value]
78
+ * @return string
79
+ */
80
+ public function __toString()
81
+ {
82
+ return __CLASS__ . '[' .
83
+ Braintree_Util::attributesToString($this->_attributes) .']';
84
+ }
85
+
86
+
87
+ // static methods redirecting to gateway
88
+
89
+ public static function find($token)
90
+ {
91
+ return Braintree_Configuration::gateway()->coinbaseAccount()->find($token);
92
+ }
93
+
94
+ public static function update($token, $attributes)
95
+ {
96
+ return Braintree_Configuration::gateway()->coinbaseAccount()->update($token, $attributes);
97
+ }
98
+
99
+ public static function delete($token)
100
+ {
101
+ return Braintree_Configuration::gateway()->coinbaseAccount()->delete($token);
102
+ }
103
+
104
+ public static function sale($token, $transactionAttribs)
105
+ {
106
+ return Braintree_Configuration::gateway()->coinbaseAccount()->sale($token, $transactionAttribs);
107
+ }
108
+ }
lib/Braintree/Collection.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Generic collection
4
+ *
5
+ * PHP Version 5
6
+ *
7
+ * Based on Generic Collection class from:
8
+ * {@link http://codeutopia.net/code/library/CU/Collection.php}
9
+ *
10
+ * @package Braintree
11
+ * @subpackage Utility
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+
15
+ class Braintree_Collection implements Countable, IteratorAggregate, ArrayAccess
16
+ {
17
+ /**
18
+ *
19
+ * @var array $_collection collection storage
20
+ */
21
+ protected $_collection = array();
22
+
23
+ /**
24
+ * Add a value into the collection
25
+ * @param string $value
26
+ */
27
+ public function add($value)
28
+ {
29
+ $this->_collection[] = $value;
30
+ }
31
+
32
+ /**
33
+ * Set index's value
34
+ * @param integer $index
35
+ * @param mixed $value
36
+ * @throws OutOfRangeException
37
+ */
38
+ public function set($index, $value)
39
+ {
40
+ if($index >= $this->count())
41
+ throw new OutOfRangeException('Index out of range');
42
+
43
+ $this->_collection[$index] = $value;
44
+ }
45
+
46
+ /**
47
+ * Remove a value from the collection
48
+ * @param integer $index index to remove
49
+ * @throws OutOfRangeException if index is out of range
50
+ */
51
+ public function remove($index)
52
+ {
53
+ if($index >= $this->count())
54
+ throw new OutOfRangeException('Index out of range');
55
+
56
+ array_splice($this->_collection, $index, 1);
57
+ }
58
+
59
+ /**
60
+ * Return value at index
61
+ * @param integer $index
62
+ * @return mixed
63
+ * @throws OutOfRangeException
64
+ */
65
+ public function get($index)
66
+ {
67
+ if($index >= $this->count())
68
+ throw new OutOfRangeException('Index out of range');
69
+
70
+ return $this->_collection[$index];
71
+ }
72
+
73
+ /**
74
+ * Determine if index exists
75
+ * @param integer $index
76
+ * @return boolean
77
+ */
78
+ public function exists($index)
79
+ {
80
+ if($index >= $this->count())
81
+ return false;
82
+
83
+ return true;
84
+ }
85
+ /**
86
+ * Return count of items in collection
87
+ * Implements countable
88
+ * @return integer
89
+ */
90
+ public function count()
91
+ {
92
+ return count($this->_collection);
93
+ }
94
+
95
+
96
+ /**
97
+ * Return an iterator
98
+ * Implements IteratorAggregate
99
+ * @return ArrayIterator
100
+ */
101
+ public function getIterator()
102
+ {
103
+ return new ArrayIterator($this->_collection);
104
+ }
105
+
106
+ /**
107
+ * Set offset to value
108
+ * Implements ArrayAccess
109
+ * @see set
110
+ * @param integer $offset
111
+ * @param mixed $value
112
+ */
113
+ public function offsetSet($offset, $value)
114
+ {
115
+ $this->set($offset, $value);
116
+ }
117
+
118
+ /**
119
+ * Unset offset
120
+ * Implements ArrayAccess
121
+ * @see remove
122
+ * @param integer $offset
123
+ */
124
+ public function offsetUnset($offset)
125
+ {
126
+ $this->remove($offset);
127
+ }
128
+
129
+ /**
130
+ * get an offset's value
131
+ * Implements ArrayAccess
132
+ * @see get
133
+ * @param integer $offset
134
+ * @return mixed
135
+ */
136
+ public function offsetGet($offset)
137
+ {
138
+ return $this->get($offset);
139
+ }
140
+
141
+ /**
142
+ * Determine if offset exists
143
+ * Implements ArrayAccess
144
+ * @see exists
145
+ * @param integer $offset
146
+ * @return boolean
147
+ */
148
+ public function offsetExists($offset)
149
+ {
150
+ return $this->exists($offset);
151
+ }
152
+
153
+ }
lib/Braintree/Configuration.php ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Configuration registry
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Utility
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ */
10
+
11
+ class Braintree_Configuration
12
+ {
13
+ public static $global;
14
+
15
+ private $_environment = null;
16
+ private $_merchantId = null;
17
+ private $_publicKey = null;
18
+ private $_privateKey = null;
19
+
20
+ /**
21
+ * Braintree API version to use
22
+ * @access public
23
+ */
24
+ const API_VERSION = 4;
25
+
26
+ public function __construct($attribs = array())
27
+ {
28
+ foreach ($attribs as $kind => $value) {
29
+ if ($kind == 'environment') {
30
+ $this->setEnvironment($value);
31
+ }
32
+ if ($kind == 'merchantId') {
33
+ $this->setMerchantId($value);
34
+ }
35
+ if ($kind == 'publicKey') {
36
+ $this->setPublicKey($value);
37
+ }
38
+ if ($kind == 'privateKey') {
39
+ $this->setPrivateKey($value);
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * resets configuration to default
46
+ * @access public
47
+ */
48
+ public static function reset()
49
+ {
50
+ self::$global = new Braintree_Configuration();
51
+ }
52
+
53
+ public static function gateway()
54
+ {
55
+ return new Braintree_Gateway(self::$global);
56
+ }
57
+
58
+ /**
59
+ *
60
+ * @access protected
61
+ * @static
62
+ * @var array valid environments, used for validation
63
+ */
64
+ private static $_validEnvironments = array(
65
+ 'development',
66
+ 'sandbox',
67
+ 'production',
68
+ 'qa',
69
+ );
70
+
71
+ /**
72
+ * resets configuration to default
73
+ * @access public
74
+ * @static
75
+ */
76
+ public static function environment($value=null)
77
+ {
78
+ if (empty($value)) {
79
+ return self::$global->getEnvironment();
80
+ }
81
+ self::$global->setEnvironment($value);
82
+ }
83
+
84
+ public static function merchantId($value=null)
85
+ {
86
+ if (empty($value)) {
87
+ return self::$global->getMerchantId();
88
+ }
89
+ self::$global->setMerchantId($value);
90
+ }
91
+
92
+ public static function publicKey($value=null)
93
+ {
94
+ if (empty($value)) {
95
+ return self::$global->getPublicKey();
96
+ }
97
+ self::$global->setPublicKey($value);
98
+ }
99
+
100
+ public static function privateKey($value=null)
101
+ {
102
+ if (empty($value)) {
103
+ return self::$global->getPrivateKey();
104
+ }
105
+ self::$global->setPrivateKey($value);
106
+ }
107
+
108
+ public function assertValid()
109
+ {
110
+ if (empty($this->_environment)) {
111
+ throw new Braintree_Exception_Configuration('environment needs to be set.');
112
+ } else if (empty($this->_merchantId)) {
113
+ throw new Braintree_Exception_Configuration('merchantId needs to be set.');
114
+ } else if (empty($this->_publicKey)) {
115
+ throw new Braintree_Exception_Configuration('publicKey needs to be set.');
116
+ } else if (empty($this->_privateKey)) {
117
+ throw new Braintree_Exception_Configuration('privateKey needs to be set.');
118
+ }
119
+ }
120
+
121
+
122
+ public function getEnvironment()
123
+ {
124
+ return $this->_environment;
125
+ }
126
+
127
+ public function setEnvironment($value)
128
+ {
129
+ if (!in_array($value, self::$_validEnvironments)) {
130
+ throw new Braintree_Exception_Configuration('"' .
131
+ $value . '" is not a valid environment.');
132
+ }
133
+ $this->_environment = $value;
134
+ }
135
+
136
+ public function getMerchantId()
137
+ {
138
+ return $this->_merchantId;
139
+ }
140
+
141
+ public function setMerchantId($value)
142
+ {
143
+ $this->_merchantId = $value;
144
+ }
145
+
146
+ public function getPublicKey()
147
+ {
148
+ return $this->_publicKey;
149
+ }
150
+
151
+ public function setPublicKey($value)
152
+ {
153
+ $this->_publicKey = $value;
154
+ }
155
+
156
+ public function getPrivateKey()
157
+ {
158
+ return $this->_privateKey;
159
+ }
160
+
161
+ public function setPrivateKey($value)
162
+ {
163
+ $this->_privateKey = $value;
164
+ }
165
+
166
+ /**
167
+ * returns the base braintree gateway URL based on config values
168
+ *
169
+ * @access public
170
+ * @param none
171
+ * @return string braintree gateway URL
172
+ */
173
+ public function baseUrl()
174
+ {
175
+ return $this->protocol() . '://' .
176
+ $this->serverName() . ':' .
177
+ $this->portNumber();
178
+ }
179
+
180
+ /**
181
+ * sets the merchant path based on merchant ID
182
+ *
183
+ * @access protected
184
+ * @param none
185
+ * @return string merchant path uri
186
+ */
187
+ public function merchantPath()
188
+ {
189
+ return '/merchants/'.$this->_merchantId;
190
+ }
191
+
192
+ /**
193
+ * sets the physical path for the location of the CA certs
194
+ *
195
+ * @access public
196
+ * @param none
197
+ * @return string filepath
198
+ */
199
+ public function caFile($sslPath = NULL)
200
+ {
201
+ $sslPath = $sslPath ? $sslPath : DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
202
+ 'ssl' . DIRECTORY_SEPARATOR;
203
+
204
+ $caPath = realpath(
205
+ dirname(__FILE__) .
206
+ $sslPath . 'api_braintreegateway_com.ca.crt'
207
+ );
208
+
209
+ if (!file_exists($caPath))
210
+ {
211
+ throw new Braintree_Exception_SSLCaFileNotFound();
212
+ }
213
+
214
+ return $caPath;
215
+ }
216
+
217
+ /**
218
+ * returns the port number depending on environment
219
+ *
220
+ * @access public
221
+ * @param none
222
+ * @return int portnumber
223
+ */
224
+ public function portNumber()
225
+ {
226
+ if ($this->sslOn()) {
227
+ return 443;
228
+ }
229
+ return getenv("GATEWAY_PORT") ? getenv("GATEWAY_PORT") : 3000;
230
+ }
231
+
232
+ /**
233
+ * returns http protocol depending on environment
234
+ *
235
+ * @access public
236
+ * @param none
237
+ * @return string http || https
238
+ */
239
+ public function protocol()
240
+ {
241
+ return $this->sslOn() ? 'https' : 'http';
242
+ }
243
+
244
+ /**
245
+ * returns gateway server name depending on environment
246
+ *
247
+ * @access public
248
+ * @param none
249
+ * @return string server domain name
250
+ */
251
+ public function serverName()
252
+ {
253
+ switch($this->_environment) {
254
+ case 'production':
255
+ $serverName = 'api.braintreegateway.com';
256
+ break;
257
+ case 'qa':
258
+ $serverName = 'gateway.qa.braintreepayments.com';
259
+ break;
260
+ case 'sandbox':
261
+ $serverName = 'api.sandbox.braintreegateway.com';
262
+ break;
263
+ case 'development':
264
+ default:
265
+ $serverName = 'localhost';
266
+ break;
267
+ }
268
+
269
+ return $serverName;
270
+ }
271
+
272
+ public function authUrl()
273
+ {
274
+ switch($this->_environment) {
275
+ case 'production':
276
+ $serverName = 'https://auth.venmo.com';
277
+ break;
278
+ case 'qa':
279
+ $serverName = 'https://auth.qa.venmo.com';
280
+ break;
281
+ case 'sandbox':
282
+ $serverName = 'https://auth.sandbox.venmo.com';
283
+ break;
284
+ case 'development':
285
+ default:
286
+ $serverName = 'http://auth.venmo.dev:9292';
287
+ break;
288
+ }
289
+
290
+ return $serverName;
291
+ }
292
+
293
+ /**
294
+ * returns boolean indicating SSL is on or off for this session,
295
+ * depending on environment
296
+ *
297
+ * @access public
298
+ * @param none
299
+ * @return boolean
300
+ */
301
+ public function sslOn()
302
+ {
303
+ switch($this->_environment) {
304
+ case 'development':
305
+ $ssl = false;
306
+ break;
307
+ case 'production':
308
+ case 'qa':
309
+ case 'sandbox':
310
+ default:
311
+ $ssl = true;
312
+ break;
313
+ }
314
+
315
+ return $ssl;
316
+ }
317
+
318
+ /**
319
+ * log message to default logger
320
+ *
321
+ * @param string $message
322
+ *
323
+ */
324
+ public function logMessage($message)
325
+ {
326
+ error_log('[Braintree] ' . $message);
327
+ }
328
+ }
329
+ Braintree_Configuration::reset();
lib/Braintree/CreditCard.php ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree CreditCard module
4
+ * Creates and manages Braintree CreditCards
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * For more detailed information on CreditCards, see {@link http://www.braintreepayments.com/gateway/credit-card-api http://www.braintreepaymentsolutions.com/gateway/credit-card-api}<br />
9
+ * For more detailed information on CreditCard verifications, see {@link http://www.braintreepayments.com/gateway/credit-card-verification-api http://www.braintreepaymentsolutions.com/gateway/credit-card-verification-api}
10
+ *
11
+ * @package Braintree
12
+ * @category Resources
13
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
14
+ *
15
+ * @property-read string $billingAddress
16
+ * @property-read string $bin
17
+ * @property-read string $cardType
18
+ * @property-read string $cardholderName
19
+ * @property-read string $createdAt
20
+ * @property-read string $customerId
21
+ * @property-read string $expirationDate
22
+ * @property-read string $expirationMonth
23
+ * @property-read string $expirationYear
24
+ * @property-read string $imageUrl
25
+ * @property-read string $last4
26
+ * @property-read string $maskedNumber
27
+ * @property-read string $token
28
+ * @property-read string $updatedAt
29
+ */
30
+ class Braintree_CreditCard extends Braintree
31
+ {
32
+ // Card Type
33
+ const AMEX = 'American Express';
34
+ const CARTE_BLANCHE = 'Carte Blanche';
35
+ const CHINA_UNION_PAY = 'China UnionPay';
36
+ const DINERS_CLUB_INTERNATIONAL = 'Diners Club';
37
+ const DISCOVER = 'Discover';
38
+ const JCB = 'JCB';
39
+ const LASER = 'Laser';
40
+ const MAESTRO = 'Maestro';
41
+ const MASTER_CARD = 'MasterCard';
42
+ const SOLO = 'Solo';
43
+ const SWITCH_TYPE = 'Switch';
44
+ const VISA = 'Visa';
45
+ const UNKNOWN = 'Unknown';
46
+
47
+ // Credit card origination location
48
+ const INTERNATIONAL = "international";
49
+ const US = "us";
50
+
51
+ const PREPAID_YES = 'Yes';
52
+ const PREPAID_NO = 'No';
53
+ const PREPAID_UNKNOWN = 'Unknown';
54
+
55
+ const PAYROLL_YES = 'Yes';
56
+ const PAYROLL_NO = 'No';
57
+ const PAYROLL_UNKNOWN = 'Unknown';
58
+
59
+ const HEALTHCARE_YES = 'Yes';
60
+ const HEALTHCARE_NO = 'No';
61
+ const HEALTHCARE_UNKNOWN = 'Unknown';
62
+
63
+ const DURBIN_REGULATED_YES = 'Yes';
64
+ const DURBIN_REGULATED_NO = 'No';
65
+ const DURBIN_REGULATED_UNKNOWN = 'Unknown';
66
+
67
+ const DEBIT_YES = 'Yes';
68
+ const DEBIT_NO = 'No';
69
+ const DEBIT_UNKNOWN = 'Unknown';
70
+
71
+ const COMMERCIAL_YES = 'Yes';
72
+ const COMMERCIAL_NO = 'No';
73
+ const COMMERCIAL_UNKNOWN = 'Unknown';
74
+
75
+ const COUNTRY_OF_ISSUANCE_UNKNOWN = "Unknown";
76
+ const ISSUING_BANK_UNKNOWN = "Unknown";
77
+
78
+ /* instance methods */
79
+ /**
80
+ * returns false if default is null or false
81
+ *
82
+ * @return boolean
83
+ */
84
+ public function isDefault()
85
+ {
86
+ return $this->default;
87
+ }
88
+
89
+ /**
90
+ * checks whether the card is expired based on the current date
91
+ *
92
+ * @return boolean
93
+ */
94
+ public function isExpired()
95
+ {
96
+ return $this->expired;
97
+ }
98
+
99
+ /**
100
+ * checks whether the card is associated with venmo sdk
101
+ *
102
+ * @return boolean
103
+ */
104
+ public function isVenmoSdk()
105
+ {
106
+ return $this->venmoSdk;
107
+ }
108
+
109
+ /**
110
+ * sets instance properties from an array of values
111
+ *
112
+ * @access protected
113
+ * @param array $creditCardAttribs array of creditcard data
114
+ * @return none
115
+ */
116
+ protected function _initialize($creditCardAttribs)
117
+ {
118
+ // set the attributes
119
+ $this->_attributes = $creditCardAttribs;
120
+
121
+ // map each address into its own object
122
+ $billingAddress = isset($creditCardAttribs['billingAddress']) ?
123
+ Braintree_Address::factory($creditCardAttribs['billingAddress']) :
124
+ null;
125
+
126
+ $subscriptionArray = array();
127
+ if (isset($creditCardAttribs['subscriptions'])) {
128
+ foreach ($creditCardAttribs['subscriptions'] AS $subscription) {
129
+ $subscriptionArray[] = Braintree_Subscription::factory($subscription);
130
+ }
131
+ }
132
+
133
+ $this->_set('subscriptions', $subscriptionArray);
134
+ $this->_set('billingAddress', $billingAddress);
135
+ $this->_set('expirationDate', $this->expirationMonth . '/' . $this->expirationYear);
136
+ $this->_set('maskedNumber', $this->bin . '******' . $this->last4);
137
+
138
+ if(isset($creditCardAttribs['verifications']) && count($creditCardAttribs['verifications']) > 0) {
139
+ $verifications = $creditCardAttribs['verifications'];
140
+ usort($verifications, array($this, '_compareCreatedAtOnVerifications'));
141
+
142
+ $this->_set('verification', Braintree_CreditCardVerification::factory($verifications[0]));
143
+ }
144
+ }
145
+
146
+ private function _compareCreatedAtOnVerifications($verificationAttrib1, $verificationAttrib2)
147
+ {
148
+ return ($verificationAttrib2['createdAt'] < $verificationAttrib1['createdAt']) ? -1 : 1;
149
+ }
150
+
151
+ /**
152
+ * returns false if comparing object is not a Braintree_CreditCard,
153
+ * or is a Braintree_CreditCard with a different id
154
+ *
155
+ * @param object $otherCreditCard customer to compare against
156
+ * @return boolean
157
+ */
158
+ public function isEqual($otherCreditCard)
159
+ {
160
+ return !($otherCreditCard instanceof Braintree_CreditCard) ? false : $this->token === $otherCreditCard->token;
161
+ }
162
+
163
+ /**
164
+ * create a printable representation of the object as:
165
+ * ClassName[property=value, property=value]
166
+ * @return string
167
+ */
168
+ public function __toString()
169
+ {
170
+ return __CLASS__ . '[' .
171
+ Braintree_Util::attributesToString($this->_attributes) .']';
172
+ }
173
+
174
+ /**
175
+ * factory method: returns an instance of Braintree_CreditCard
176
+ * to the requesting method, with populated properties
177
+ *
178
+ * @ignore
179
+ * @return object instance of Braintree_CreditCard
180
+ */
181
+ public static function factory($attributes)
182
+ {
183
+ $defaultAttributes = array(
184
+ 'bin' => '',
185
+ 'expirationMonth' => '',
186
+ 'expirationYear' => '',
187
+ 'last4' => '',
188
+ );
189
+
190
+ $instance = new self();
191
+ $instance->_initialize(array_merge($defaultAttributes, $attributes));
192
+ return $instance;
193
+ }
194
+
195
+
196
+ // static methods redirecting to gateway
197
+
198
+ public static function create($attribs)
199
+ {
200
+ return Braintree_Configuration::gateway()->creditCard()->create($attribs);
201
+ }
202
+
203
+ public static function createNoValidate($attribs)
204
+ {
205
+ return Braintree_Configuration::gateway()->creditCard()->createNoValidate($attribs);
206
+ }
207
+
208
+ public static function createFromTransparentRedirect($queryString)
209
+ {
210
+ return Braintree_Configuration::gateway()->creditCard()->createFromTransparentRedirect($queryString);
211
+ }
212
+
213
+ public static function createCreditCardUrl()
214
+ {
215
+ return Braintree_Configuration::gateway()->creditCard()->createCreditCardUrl();
216
+ }
217
+
218
+ public static function expired()
219
+ {
220
+ return Braintree_Configuration::gateway()->creditCard()->expired();
221
+ }
222
+
223
+ public static function fetchExpired($ids)
224
+ {
225
+ return Braintree_Configuration::gateway()->creditCard()->fetchExpired($ids);
226
+ }
227
+
228
+ public static function expiringBetween($startDate, $endDate)
229
+ {
230
+ return Braintree_Configuration::gateway()->creditCard()->expiringBetween($startDate, $endDate);
231
+ }
232
+
233
+ public static function fetchExpiring($startDate, $endDate, $ids)
234
+ {
235
+ return Braintree_Configuration::gateway()->creditCard()->fetchExpiring($startDate, $endDate, $ids);
236
+ }
237
+
238
+ public static function find($token)
239
+ {
240
+ return Braintree_Configuration::gateway()->creditCard()->find($token);
241
+ }
242
+
243
+ public static function fromNonce($nonce)
244
+ {
245
+ return Braintree_Configuration::gateway()->creditCard()->fromNonce($nonce);
246
+ }
247
+
248
+ public static function credit($token, $transactionAttribs)
249
+ {
250
+ return Braintree_Configuration::gateway()->creditCard()->credit($token, $transactionAttribs);
251
+ }
252
+
253
+ public static function creditNoValidate($token, $transactionAttribs)
254
+ {
255
+ return Braintree_Configuration::gateway()->creditCard()->creditNoValidate($token, $transactionAttribs);
256
+ }
257
+
258
+ public static function sale($token, $transactionAttribs)
259
+ {
260
+ return Braintree_Configuration::gateway()->creditCard()->sale($token, $transactionAttribs);
261
+ }
262
+
263
+ public static function saleNoValidate($token, $transactionAttribs)
264
+ {
265
+ return Braintree_Configuration::gateway()->creditCard()->saleNoValidate($token, $transactionAttribs);
266
+ }
267
+
268
+ public static function update($token, $attributes)
269
+ {
270
+ return Braintree_Configuration::gateway()->creditCard()->update($token, $attributes);
271
+ }
272
+
273
+ public static function updateNoValidate($token, $attributes)
274
+ {
275
+ return Braintree_Configuration::gateway()->creditCard()->updateNoValidate($token, $attributes);
276
+ }
277
+
278
+ public static function updateCreditCardUrl()
279
+ {
280
+ return Braintree_Configuration::gateway()->creditCard()->updateCreditCardUrl();
281
+ }
282
+
283
+ public static function updateFromTransparentRedirect($queryString)
284
+ {
285
+ return Braintree_Configuration::gateway()->creditCard()->updateFromTransparentRedirect($queryString);
286
+ }
287
+
288
+ public static function delete($token)
289
+ {
290
+ return Braintree_Configuration::gateway()->creditCard()->delete($token);
291
+ }
292
+ }
lib/Braintree/CreditCardGateway.php ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree CreditCardGateway module
4
+ * Creates and manages Braintree CreditCards
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * For more detailed information on CreditCards, see {@link http://www.braintreepayments.com/gateway/credit-card-api http://www.braintreepaymentsolutions.com/gateway/credit-card-api}<br />
9
+ * For more detailed information on CreditCard verifications, see {@link http://www.braintreepayments.com/gateway/credit-card-verification-api http://www.braintreepaymentsolutions.com/gateway/credit-card-verification-api}
10
+ *
11
+ * @package Braintree
12
+ * @category Resources
13
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
14
+ */
15
+ class Braintree_CreditCardGateway
16
+ {
17
+ private $_gateway;
18
+ private $_config;
19
+ private $_http;
20
+
21
+ public function __construct($gateway)
22
+ {
23
+ $this->_gateway = $gateway;
24
+ $this->_config = $gateway->config;
25
+ $this->_http = new Braintree_Http($gateway->config);
26
+ }
27
+
28
+ public function create($attribs)
29
+ {
30
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
31
+ return $this->_doCreate('/payment_methods', array('credit_card' => $attribs));
32
+ }
33
+
34
+ /**
35
+ * attempts the create operation assuming all data will validate
36
+ * returns a Braintree_CreditCard object instead of a Result
37
+ *
38
+ * @access public
39
+ * @param array $attribs
40
+ * @return object
41
+ * @throws Braintree_Exception_ValidationError
42
+ */
43
+ public function createNoValidate($attribs)
44
+ {
45
+ $result = $this->create($attribs);
46
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
47
+ }
48
+ /**
49
+ * create a customer from a TransparentRedirect operation
50
+ *
51
+ * @access public
52
+ * @param array $attribs
53
+ * @return object
54
+ */
55
+ public function createFromTransparentRedirect($queryString)
56
+ {
57
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
58
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
59
+ $queryString
60
+ );
61
+ return $this->_doCreate(
62
+ '/payment_methods/all/confirm_transparent_redirect_request',
63
+ array('id' => $params['id'])
64
+ );
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @access public
70
+ * @param none
71
+ * @return string
72
+ */
73
+ public function createCreditCardUrl()
74
+ {
75
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
76
+ return $this->_config->baseUrl() . $this->_config->merchantPath() .
77
+ '/payment_methods/all/create_via_transparent_redirect_request';
78
+ }
79
+
80
+ /**
81
+ * returns a ResourceCollection of expired credit cards
82
+ * @return object ResourceCollection
83
+ */
84
+ public function expired()
85
+ {
86
+ $path = $this->_config->merchantPath() . '/payment_methods/all/expired_ids';
87
+ $response = $this->_http->post($path);
88
+ $pager = array(
89
+ 'object' => $this,
90
+ 'method' => 'fetchExpired',
91
+ 'methodArgs' => array()
92
+ );
93
+
94
+ return new Braintree_ResourceCollection($response, $pager);
95
+ }
96
+
97
+ public function fetchExpired($ids)
98
+ {
99
+ $path = $this->_config->merchantPath() . "/payment_methods/all/expired";
100
+ $response = $this->_http->post($path, array('search' => array('ids' => $ids)));
101
+
102
+ return Braintree_Util::extractattributeasarray(
103
+ $response['paymentMethods'],
104
+ 'creditCard'
105
+ );
106
+ }
107
+ /**
108
+ * returns a ResourceCollection of credit cards expiring between start/end
109
+ *
110
+ * @return object ResourceCollection
111
+ */
112
+ public function expiringBetween($startDate, $endDate)
113
+ {
114
+ $queryPath = $this->_config->merchantPath() . '/payment_methods/all/expiring_ids?start=' . date('mY', $startDate) . '&end=' . date('mY', $endDate);
115
+ $response = $this->_http->post($queryPath);
116
+ $pager = array(
117
+ 'object' => $this,
118
+ 'method' => 'fetchExpiring',
119
+ 'methodArgs' => array($startDate, $endDate)
120
+ );
121
+
122
+ return new Braintree_ResourceCollection($response, $pager);
123
+ }
124
+
125
+ public function fetchExpiring($startDate, $endDate, $ids)
126
+ {
127
+ $queryPath = $this->_config->merchantPath() . '/payment_methods/all/expiring?start=' . date('mY', $startDate) . '&end=' . date('mY', $endDate);
128
+ $response = $this->_http->post($queryPath, array('search' => array('ids' => $ids)));
129
+
130
+ return Braintree_Util::extractAttributeAsArray(
131
+ $response['paymentMethods'],
132
+ 'creditCard'
133
+ );
134
+ }
135
+
136
+ /**
137
+ * find a creditcard by token
138
+ *
139
+ * @access public
140
+ * @param string $token credit card unique id
141
+ * @return object Braintree_CreditCard
142
+ * @throws Braintree_Exception_NotFound
143
+ */
144
+ public function find($token)
145
+ {
146
+ $this->_validateId($token);
147
+ try {
148
+ $path = $this->_config->merchantPath() . '/payment_methods/credit_card/' . $token;
149
+ $response = $this->_http->get($path);
150
+ return Braintree_CreditCard::factory($response['creditCard']);
151
+ } catch (Braintree_Exception_NotFound $e) {
152
+ throw new Braintree_Exception_NotFound(
153
+ 'credit card with token ' . $token . ' not found'
154
+ );
155
+ }
156
+
157
+ }
158
+
159
+ /**
160
+ * Convert a payment method nonce to a credit card
161
+ *
162
+ * @access public
163
+ * @param string $nonce payment method nonce
164
+ * @return object Braintree_CreditCard
165
+ * @throws Braintree_Exception_NotFound
166
+ */
167
+ public function fromNonce($nonce)
168
+ {
169
+ $this->_validateId($nonce, "nonce");
170
+ try {
171
+ $path = $this->_config->merchantPath() . '/payment_methods/from_nonce/' . $nonce;
172
+ $response = $this->_http->get($path);
173
+ return Braintree_CreditCard::factory($response['creditCard']);
174
+ } catch (Braintree_Exception_NotFound $e) {
175
+ throw new Braintree_Exception_NotFound(
176
+ 'credit card with nonce ' . $nonce . ' locked, consumed or not found'
177
+ );
178
+ }
179
+
180
+ }
181
+
182
+ /**
183
+ * create a credit on the card for the passed transaction
184
+ *
185
+ * @access public
186
+ * @param array $attribs
187
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
188
+ */
189
+ public function credit($token, $transactionAttribs)
190
+ {
191
+ $this->_validateId($token);
192
+ return Braintree_Transaction::credit(
193
+ array_merge(
194
+ $transactionAttribs,
195
+ array('paymentMethodToken' => $token)
196
+ )
197
+ );
198
+ }
199
+
200
+ /**
201
+ * create a credit on this card, assuming validations will pass
202
+ *
203
+ * returns a Braintree_Transaction object on success
204
+ *
205
+ * @access public
206
+ * @param array $attribs
207
+ * @return object Braintree_Transaction
208
+ * @throws Braintree_Exception_ValidationError
209
+ */
210
+ public function creditNoValidate($token, $transactionAttribs)
211
+ {
212
+ $result = $this->credit($token, $transactionAttribs);
213
+ return Braintree_Util::returnObjectOrThrowException('Transaction', $result);
214
+ }
215
+
216
+ /**
217
+ * create a new sale for the current card
218
+ *
219
+ * @param string $token
220
+ * @param array $transactionAttribs
221
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
222
+ * @see Braintree_Transaction::sale()
223
+ */
224
+ public function sale($token, $transactionAttribs)
225
+ {
226
+ $this->_validateId($token);
227
+ return Braintree_Transaction::sale(
228
+ array_merge(
229
+ $transactionAttribs,
230
+ array('paymentMethodToken' => $token)
231
+ )
232
+ );
233
+ }
234
+
235
+ /**
236
+ * create a new sale using this card, assuming validations will pass
237
+ *
238
+ * returns a Braintree_Transaction object on success
239
+ *
240
+ * @access public
241
+ * @param array $transactionAttribs
242
+ * @param string $token
243
+ * @return object Braintree_Transaction
244
+ * @throws Braintree_Exception_ValidationsFailed
245
+ * @see Braintree_Transaction::sale()
246
+ */
247
+ public function saleNoValidate($token, $transactionAttribs)
248
+ {
249
+ $result = $this->sale($token, $transactionAttribs);
250
+ return Braintree_Util::returnObjectOrThrowException('Transaction', $result);
251
+ }
252
+
253
+ /**
254
+ * updates the creditcard record
255
+ *
256
+ * if calling this method in context, $token
257
+ * is the 2nd attribute. $token is not sent in object context.
258
+ *
259
+ * @access public
260
+ * @param array $attributes
261
+ * @param string $token (optional)
262
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
263
+ */
264
+ public function update($token, $attributes)
265
+ {
266
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
267
+ $this->_validateId($token);
268
+ return $this->_doUpdate('put', '/payment_methods/credit_card/' . $token, array('creditCard' => $attributes));
269
+ }
270
+
271
+ /**
272
+ * update a creditcard record, assuming validations will pass
273
+ *
274
+ * if calling this method in context, $token
275
+ * is the 2nd attribute. $token is not sent in object context.
276
+ * returns a Braintree_CreditCard object on success
277
+ *
278
+ * @access public
279
+ * @param array $attributes
280
+ * @param string $token
281
+ * @return object Braintree_CreditCard
282
+ * @throws Braintree_Exception_ValidationsFailed
283
+ */
284
+ public function updateNoValidate($token, $attributes)
285
+ {
286
+ $result = $this->update($token, $attributes);
287
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
288
+ }
289
+ /**
290
+ *
291
+ * @access public
292
+ * @param none
293
+ * @return string
294
+ */
295
+ public function updateCreditCardUrl()
296
+ {
297
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
298
+ return $this->_config->baseUrl() . $this->_config->merchantPath() .
299
+ '/payment_methods/all/update_via_transparent_redirect_request';
300
+ }
301
+
302
+ /**
303
+ * update a customer from a TransparentRedirect operation
304
+ *
305
+ * @access public
306
+ * @param array $attribs
307
+ * @return object
308
+ */
309
+ public function updateFromTransparentRedirect($queryString)
310
+ {
311
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
312
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
313
+ $queryString
314
+ );
315
+ return $this->_doUpdate(
316
+ 'post',
317
+ '/payment_methods/all/confirm_transparent_redirect_request',
318
+ array('id' => $params['id'])
319
+ );
320
+ }
321
+
322
+ public function delete($token)
323
+ {
324
+ $this->_validateId($token);
325
+ $path = $this->_config->merchantPath() . '/payment_methods/credit_card/' . $token;
326
+ $this->_http->delete($path);
327
+ return new Braintree_Result_Successful();
328
+ }
329
+
330
+ private static function baseOptions()
331
+ {
332
+ return array('makeDefault', 'verificationMerchantAccountId', 'verifyCard', 'verificationAmount', 'venmoSdkSession');
333
+ }
334
+
335
+ private static function baseSignature($options)
336
+ {
337
+ return array(
338
+ 'billingAddressId', 'cardholderName', 'cvv', 'number', 'deviceSessionId',
339
+ 'expirationDate', 'expirationMonth', 'expirationYear', 'token', 'venmoSdkPaymentMethodCode',
340
+ 'deviceData', 'fraudMerchantId', 'paymentMethodNonce',
341
+ array('options' => $options),
342
+ array(
343
+ 'billingAddress' => array(
344
+ 'firstName',
345
+ 'lastName',
346
+ 'company',
347
+ 'countryCodeAlpha2',
348
+ 'countryCodeAlpha3',
349
+ 'countryCodeNumeric',
350
+ 'countryName',
351
+ 'extendedAddress',
352
+ 'locality',
353
+ 'region',
354
+ 'postalCode',
355
+ 'streetAddress'
356
+ ),
357
+ ),
358
+ );
359
+ }
360
+
361
+ public static function createSignature()
362
+ {
363
+ $options = self::baseOptions();
364
+ $options[] = "failOnDuplicatePaymentMethod";
365
+ $signature = self::baseSignature($options);
366
+ $signature[] = 'customerId';
367
+ return $signature;
368
+ }
369
+
370
+ public static function updateSignature()
371
+ {
372
+ $signature = self::baseSignature(self::baseOptions());
373
+
374
+ $updateExistingBillingSignature = array(
375
+ array(
376
+ 'options' => array(
377
+ 'updateExisting'
378
+ )
379
+ )
380
+ );
381
+
382
+ foreach($signature AS $key => $value) {
383
+ if(is_array($value) and array_key_exists('billingAddress', $value)) {
384
+ $signature[$key]['billingAddress'] = array_merge_recursive($value['billingAddress'], $updateExistingBillingSignature);
385
+ }
386
+ }
387
+
388
+ return $signature;
389
+ }
390
+
391
+ /**
392
+ * sends the create request to the gateway
393
+ *
394
+ * @ignore
395
+ * @param string $subPath
396
+ * @param array $params
397
+ * @return mixed
398
+ */
399
+ public function _doCreate($subPath, $params)
400
+ {
401
+ $fullPath = $this->_config->merchantPath() . $subPath;
402
+ $response = $this->_http->post($fullPath, $params);
403
+
404
+ return $this->_verifyGatewayResponse($response);
405
+ }
406
+
407
+ /**
408
+ * verifies that a valid credit card identifier is being used
409
+ * @ignore
410
+ * @param string $identifier
411
+ * @param Optional $string $identifierType type of identifier supplied, default "token"
412
+ * @throws InvalidArgumentException
413
+ */
414
+ private function _validateId($identifier = null, $identifierType = "token")
415
+ {
416
+ if (empty($identifier)) {
417
+ throw new InvalidArgumentException(
418
+ 'expected credit card id to be set'
419
+ );
420
+ }
421
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $identifier)) {
422
+ throw new InvalidArgumentException(
423
+ $identifier . ' is an invalid credit card ' . $identifierType . '.'
424
+ );
425
+ }
426
+ }
427
+
428
+ /**
429
+ * sends the update request to the gateway
430
+ *
431
+ * @ignore
432
+ * @param string $url
433
+ * @param array $params
434
+ * @return mixed
435
+ */
436
+ private function _doUpdate($httpVerb, $subPath, $params)
437
+ {
438
+ $fullPath = $this->_config->merchantPath() . $subPath;
439
+ $response = $this->_http->$httpVerb($fullPath, $params);
440
+ return $this->_verifyGatewayResponse($response);
441
+ }
442
+
443
+ /**
444
+ * generic method for validating incoming gateway responses
445
+ *
446
+ * creates a new Braintree_CreditCard object and encapsulates
447
+ * it inside a Braintree_Result_Successful object, or
448
+ * encapsulates a Braintree_Errors object inside a Result_Error
449
+ * alternatively, throws an Unexpected exception if the response is invalid.
450
+ *
451
+ * @ignore
452
+ * @param array $response gateway response values
453
+ * @return object Result_Successful or Result_Error
454
+ * @throws Braintree_Exception_Unexpected
455
+ */
456
+ private function _verifyGatewayResponse($response)
457
+ {
458
+ if (isset($response['creditCard'])) {
459
+ // return a populated instance of Braintree_Address
460
+ return new Braintree_Result_Successful(
461
+ Braintree_CreditCard::factory($response['creditCard'])
462
+ );
463
+ } else if (isset($response['apiErrorResponse'])) {
464
+ return new Braintree_Result_Error($response['apiErrorResponse']);
465
+ } else {
466
+ throw new Braintree_Exception_Unexpected(
467
+ "Expected address or apiErrorResponse"
468
+ );
469
+ }
470
+ }
471
+ }
lib/Braintree/CreditCardVerification.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CreditCardVerification extends Braintree_Result_CreditCardVerification
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self($attributes);
7
+ return $instance;
8
+ }
9
+
10
+
11
+ // static methods redirecting to gateway
12
+
13
+ public static function fetch($query, $ids)
14
+ {
15
+ return Braintree_Configuration::gateway()->creditCardVerification()->fetch($query, $ids);
16
+ }
17
+
18
+ public static function search($query)
19
+ {
20
+ return Braintree_Configuration::gateway()->creditCardVerification()->search($query);
21
+ }
22
+ }
lib/Braintree/CreditCardVerificationGateway.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CreditCardVerificationGateway
3
+ {
4
+ private $_gateway;
5
+ private $_config;
6
+ private $_http;
7
+
8
+ public function __construct($gateway)
9
+ {
10
+ $this->_gateway = $gateway;
11
+ $this->_config = $gateway->config;
12
+ $this->_http = new Braintree_Http($gateway->config);
13
+ }
14
+
15
+ public function fetch($query, $ids)
16
+ {
17
+ $criteria = array();
18
+ foreach ($query as $term) {
19
+ $criteria[$term->name] = $term->toparam();
20
+ }
21
+ $criteria["ids"] = Braintree_CreditCardVerificationSearch::ids()->in($ids)->toparam();
22
+ $path = $this->_config->merchantPath() . '/verifications/advanced_search';
23
+ $response = $this->_http->post($path, array('search' => $criteria));
24
+
25
+ return Braintree_Util::extractattributeasarray(
26
+ $response['creditCardVerifications'],
27
+ 'verification'
28
+ );
29
+ }
30
+
31
+ public function search($query)
32
+ {
33
+ $criteria = array();
34
+ foreach ($query as $term) {
35
+ $criteria[$term->name] = $term->toparam();
36
+ }
37
+
38
+ $path = $this->_config->merchantPath() . '/verifications/advanced_search_ids';
39
+ $response = $this->_http->post($path, array('search' => $criteria));
40
+ $pager = array(
41
+ 'object' => $this,
42
+ 'method' => 'fetch',
43
+ 'methodArgs' => array($query)
44
+ );
45
+
46
+ return new Braintree_ResourceCollection($response, $pager);
47
+ }
48
+ }
lib/Braintree/CreditCardVerificationSearch.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CreditCardVerificationSearch
3
+ {
4
+ static function id() { return new Braintree_TextNode('id'); }
5
+ static function creditCardCardholderName() { return new Braintree_TextNode('credit_card_cardholder_name'); }
6
+
7
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
8
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
9
+
10
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
11
+
12
+ static function creditCardCardType()
13
+ {
14
+ return new Braintree_MultipleValueNode("credit_card_card_type", array(
15
+ Braintree_CreditCard::AMEX,
16
+ Braintree_CreditCard::CARTE_BLANCHE,
17
+ Braintree_CreditCard::CHINA_UNION_PAY,
18
+ Braintree_CreditCard::DINERS_CLUB_INTERNATIONAL,
19
+ Braintree_CreditCard::DISCOVER,
20
+ Braintree_CreditCard::JCB,
21
+ Braintree_CreditCard::LASER,
22
+ Braintree_CreditCard::MAESTRO,
23
+ Braintree_CreditCard::MASTER_CARD,
24
+ Braintree_CreditCard::SOLO,
25
+ Braintree_CreditCard::SWITCH_TYPE,
26
+ Braintree_CreditCard::VISA,
27
+ Braintree_CreditCard::UNKNOWN
28
+ ));
29
+ }
30
+
31
+
32
+ static function createdAt() { return new Braintree_RangeNode("created_at"); }
33
+ }
lib/Braintree/Customer.php ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Customer module
4
+ * Creates and manages Customers
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * For more detailed information on Customers, see {@link http://www.braintreepayments.com/gateway/customer-api http://www.braintreepaymentsolutions.com/gateway/customer-api}
9
+ *
10
+ * @package Braintree
11
+ * @category Resources
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ *
14
+ * @property-read array $addresses
15
+ * @property-read array $applePayCards
16
+ * @property-read string $company
17
+ * @property-read string $createdAt
18
+ * @property-read array $creditCards
19
+ * @property-read array $coinbaseAccounts
20
+ * @property-read array $paypalAccounts
21
+ * @property-read array $customFields custom fields passed with the request
22
+ * @property-read string $email
23
+ * @property-read string $fax
24
+ * @property-read string $firstName
25
+ * @property-read string $id
26
+ * @property-read string $lastName
27
+ * @property-read string $phone
28
+ * @property-read string $updatedAt
29
+ * @property-read string $website
30
+ */
31
+ class Braintree_Customer extends Braintree
32
+ {
33
+ public static function all()
34
+ {
35
+ return Braintree_Configuration::gateway()->customer()->all();
36
+ }
37
+
38
+ public static function fetch($query, $ids)
39
+ {
40
+ return Braintree_Configuration::gateway()->customer()->fetch($query, $ids);
41
+ }
42
+
43
+ public static function create($attribs = array())
44
+ {
45
+ return Braintree_Configuration::gateway()->customer()->create($attribs);
46
+ }
47
+
48
+ public static function createNoValidate($attribs = array())
49
+ {
50
+ return Braintree_Configuration::gateway()->customer()->createNoValidate($attribs);
51
+ }
52
+
53
+ public static function createFromTransparentRedirect($queryString)
54
+ {
55
+ return Braintree_Configuration::gateway()->customer()->createFromTransparentRedirect($queryString);
56
+ }
57
+
58
+ public static function createCustomerUrl()
59
+ {
60
+ return Braintree_Configuration::gateway()->customer()->createCustomerUrl();
61
+ }
62
+
63
+ public static function find($id)
64
+ {
65
+ return Braintree_Configuration::gateway()->customer()->find($id);
66
+ }
67
+
68
+ public static function credit($customerId, $transactionAttribs)
69
+ {
70
+ return Braintree_Configuration::gateway()->customer()->credit($customerId, $transactionAttribs);
71
+ }
72
+
73
+ public static function creditNoValidate($customerId, $transactionAttribs)
74
+ {
75
+ return Braintree_Configuration::gateway()->customer()->creditNoValidate($customerId, $transactionAttribs);
76
+ }
77
+
78
+ public static function delete($customerId)
79
+ {
80
+ return Braintree_Configuration::gateway()->customer()->delete($customerId);
81
+ }
82
+
83
+ public static function sale($customerId, $transactionAttribs)
84
+ {
85
+ return Braintree_Configuration::gateway()->customer()->sale($customerId, $transactionAttribs);
86
+ }
87
+
88
+ public static function saleNoValidate($customerId, $transactionAttribs)
89
+ {
90
+ return Braintree_Configuration::gateway()->customer()->saleNoValidate($customerId, $transactionAttribs);
91
+ }
92
+
93
+ public static function search($query)
94
+ {
95
+ return Braintree_Configuration::gateway()->customer()->search($query);
96
+ }
97
+
98
+ public static function update($customerId, $attributes)
99
+ {
100
+ return Braintree_Configuration::gateway()->customer()->update($customerId, $attributes);
101
+ }
102
+
103
+ public static function updateNoValidate($customerId, $attributes)
104
+ {
105
+ return Braintree_Configuration::gateway()->customer()->updateNoValidate($customerId, $attributes);
106
+ }
107
+
108
+ public static function updateCustomerUrl()
109
+ {
110
+ return Braintree_Configuration::gateway()->customer()->updateCustomerUrl();
111
+ }
112
+
113
+ public static function updateFromTransparentRedirect($queryString)
114
+ {
115
+ return Braintree_Configuration::gateway()->customer()->updateFromTransparentRedirect($queryString);
116
+ }
117
+
118
+ /* instance methods */
119
+
120
+ /**
121
+ * sets instance properties from an array of values
122
+ *
123
+ * @ignore
124
+ * @access protected
125
+ * @param array $customerAttribs array of customer data
126
+ * @return none
127
+ */
128
+ protected function _initialize($customerAttribs)
129
+ {
130
+ // set the attributes
131
+ $this->_attributes = $customerAttribs;
132
+
133
+ // map each address into its own object
134
+ $addressArray = array();
135
+ if (isset($customerAttribs['addresses'])) {
136
+
137
+ foreach ($customerAttribs['addresses'] AS $address) {
138
+ $addressArray[] = Braintree_Address::factory($address);
139
+ }
140
+ }
141
+ $this->_set('addresses', $addressArray);
142
+
143
+ // map each creditCard into its own object
144
+ $creditCardArray = array();
145
+ if (isset($customerAttribs['creditCards'])) {
146
+ foreach ($customerAttribs['creditCards'] AS $creditCard) {
147
+ $creditCardArray[] = Braintree_CreditCard::factory($creditCard);
148
+ }
149
+ }
150
+ $this->_set('creditCards', $creditCardArray);
151
+
152
+ // map each coinbaseAccount into its own object
153
+ $coinbaseAccountArray = array();
154
+ if (isset($customerAttribs['coinbaseAccounts'])) {
155
+ foreach ($customerAttribs['coinbaseAccounts'] AS $coinbaseAccount) {
156
+ $coinbaseAccountArray[] = Braintree_CoinbaseAccount::factory($coinbaseAccount);
157
+ }
158
+ }
159
+ $this->_set('coinbaseAccounts', $coinbaseAccountArray);
160
+
161
+ // map each paypalAccount into its own object
162
+ $paypalAccountArray = array();
163
+ if (isset($customerAttribs['paypalAccounts'])) {
164
+ foreach ($customerAttribs['paypalAccounts'] AS $paypalAccount) {
165
+ $paypalAccountArray[] = Braintree_PayPalAccount::factory($paypalAccount);
166
+ }
167
+ }
168
+ $this->_set('paypalAccounts', $paypalAccountArray);
169
+
170
+ // map each applePayCard into its own object
171
+ $applePayCardArray = array();
172
+ if (isset($customerAttribs['applePayCards'])) {
173
+ foreach ($customerAttribs['applePayCards'] AS $applePayCard) {
174
+ $applePayCardArray[] = Braintree_applePayCard::factory($applePayCard);
175
+ }
176
+ }
177
+ $this->_set('applePayCards', $applePayCardArray);
178
+ }
179
+
180
+ /**
181
+ * returns a string representation of the customer
182
+ * @return string
183
+ */
184
+ public function __toString()
185
+ {
186
+ return __CLASS__ . '[' .
187
+ Braintree_Util::attributesToString($this->_attributes) .']';
188
+ }
189
+
190
+ /**
191
+ * returns false if comparing object is not a Braintree_Customer,
192
+ * or is a Braintree_Customer with a different id
193
+ *
194
+ * @param object $otherCust customer to compare against
195
+ * @return boolean
196
+ */
197
+ public function isEqual($otherCust)
198
+ {
199
+ return !($otherCust instanceof Braintree_Customer) ? false : $this->id === $otherCust->id;
200
+ }
201
+
202
+ /**
203
+ * returns an array containt all of the customer's payment methods
204
+ *
205
+ * @return array
206
+ */
207
+ public function paymentMethods()
208
+ {
209
+ return array_merge($this->creditCards, $this->paypalAccounts, $this->applePayCards, $this->coinbaseAccounts);
210
+ }
211
+
212
+ /**
213
+ * returns the customer's default payment method
214
+ *
215
+ * @return object Braintree_CreditCard or Braintree_PayPalAccount
216
+ */
217
+ public function defaultPaymentMethod()
218
+ {
219
+ $defaultPaymentMethods = array_filter($this->paymentMethods(), 'Braintree_Customer::_defaultPaymentMethodFilter');
220
+ return current($defaultPaymentMethods);
221
+ }
222
+
223
+ public static function _defaultPaymentMethodFilter($paymentMethod)
224
+ {
225
+ return $paymentMethod->isDefault();
226
+ }
227
+
228
+ /* private class properties */
229
+
230
+ /**
231
+ * @access protected
232
+ * @var array registry of customer data
233
+ */
234
+ protected $_attributes = array(
235
+ 'addresses' => '',
236
+ 'company' => '',
237
+ 'creditCards' => '',
238
+ 'email' => '',
239
+ 'fax' => '',
240
+ 'firstName' => '',
241
+ 'id' => '',
242
+ 'lastName' => '',
243
+ 'phone' => '',
244
+ 'createdAt' => '',
245
+ 'updatedAt' => '',
246
+ 'website' => '',
247
+ );
248
+
249
+ /**
250
+ * factory method: returns an instance of Braintree_Customer
251
+ * to the requesting method, with populated properties
252
+ *
253
+ * @ignore
254
+ * @return object instance of Braintree_Customer
255
+ */
256
+ public static function factory($attributes)
257
+ {
258
+ $instance = new Braintree_Customer();
259
+ $instance->_initialize($attributes);
260
+ return $instance;
261
+ }
262
+ }
lib/Braintree/CustomerGateway.php ADDED
@@ -0,0 +1,594 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree CustomerGateway module
4
+ * Creates and manages Customers
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * For more detailed information on Customers, see {@link http://www.braintreepayments.com/gateway/customer-api http://www.braintreepaymentsolutions.com/gateway/customer-api}
9
+ *
10
+ * @package Braintree
11
+ * @category Resources
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_CustomerGateway
15
+ {
16
+ private $_gateway;
17
+ private $_config;
18
+ private $_http;
19
+
20
+ public function __construct($gateway)
21
+ {
22
+ $this->_gateway = $gateway;
23
+ $this->_config = $gateway->config;
24
+ $this->_http = new Braintree_Http($gateway->config);
25
+ }
26
+
27
+ public function all()
28
+ {
29
+ $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
30
+ $response = $this->_http->post($path);
31
+ $pager = array(
32
+ 'object' => $this,
33
+ 'method' => 'fetch',
34
+ 'methodArgs' => array(array())
35
+ );
36
+
37
+ return new Braintree_ResourceCollection($response, $pager);
38
+ }
39
+
40
+ public function fetch($query, $ids)
41
+ {
42
+ $criteria = array();
43
+ foreach ($query as $term) {
44
+ $criteria[$term->name] = $term->toparam();
45
+ }
46
+ $criteria["ids"] = Braintree_CustomerSearch::ids()->in($ids)->toparam();
47
+ $path = $this->_config->merchantPath() . '/customers/advanced_search';
48
+ $response = $this->_http->post($path, array('search' => $criteria));
49
+
50
+ return Braintree_Util::extractattributeasarray(
51
+ $response['customers'],
52
+ 'customer'
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Creates a customer using the given +attributes+. If <tt>:id</tt> is not passed,
58
+ * the gateway will generate it.
59
+ *
60
+ * <code>
61
+ * $result = Braintree_Customer::create(array(
62
+ * 'first_name' => 'John',
63
+ * 'last_name' => 'Smith',
64
+ * 'company' => 'Smith Co.',
65
+ * 'email' => 'john@smith.com',
66
+ * 'website' => 'www.smithco.com',
67
+ * 'fax' => '419-555-1234',
68
+ * 'phone' => '614-555-1234'
69
+ * ));
70
+ * if($result->success) {
71
+ * echo 'Created customer ' . $result->customer->id;
72
+ * } else {
73
+ * echo 'Could not create customer, see result->errors';
74
+ * }
75
+ * </code>
76
+ *
77
+ * @access public
78
+ * @param array $attribs
79
+ * @return object Result, either Successful or Error
80
+ */
81
+ public function create($attribs = array())
82
+ {
83
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
84
+ return $this->_doCreate('/customers', array('customer' => $attribs));
85
+ }
86
+
87
+ /**
88
+ * attempts the create operation assuming all data will validate
89
+ * returns a Braintree_Customer object instead of a Result
90
+ *
91
+ * @access public
92
+ * @param array $attribs
93
+ * @return object
94
+ * @throws Braintree_Exception_ValidationError
95
+ */
96
+ public function createNoValidate($attribs = array())
97
+ {
98
+ $result = $this->create($attribs);
99
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
100
+ }
101
+ /**
102
+ * create a customer from a TransparentRedirect operation
103
+ *
104
+ * @access public
105
+ * @param array $attribs
106
+ * @return object
107
+ */
108
+ public function createFromTransparentRedirect($queryString)
109
+ {
110
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
111
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
112
+ $queryString
113
+ );
114
+ return $this->_doCreate(
115
+ '/customers/all/confirm_transparent_redirect_request',
116
+ array('id' => $params['id'])
117
+ );
118
+ }
119
+
120
+ /**
121
+ *
122
+ * @access public
123
+ * @param none
124
+ * @return string
125
+ */
126
+ public function createCustomerUrl()
127
+ {
128
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
129
+ return $this->_config->baseUrl() . $this->_config->merchantPath() .
130
+ '/customers/all/create_via_transparent_redirect_request';
131
+ }
132
+
133
+
134
+ /**
135
+ * creates a full array signature of a valid create request
136
+ * @return array gateway create request format
137
+ */
138
+ public static function createSignature()
139
+ {
140
+
141
+ $creditCardSignature = Braintree_CreditCardGateway::createSignature();
142
+ unset($creditCardSignature['customerId']);
143
+ $signature = array(
144
+ 'id', 'company', 'email', 'fax', 'firstName',
145
+ 'lastName', 'phone', 'website', 'deviceData',
146
+ 'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce',
147
+ array('creditCard' => $creditCardSignature),
148
+ array('customFields' => array('_anyKey_')),
149
+ );
150
+ return $signature;
151
+ }
152
+
153
+ /**
154
+ * creates a full array signature of a valid update request
155
+ * @return array update request format
156
+ */
157
+ public static function updateSignature()
158
+ {
159
+ $creditCardSignature = Braintree_CreditCardGateway::updateSignature();
160
+
161
+ foreach($creditCardSignature AS $key => $value) {
162
+ if(is_array($value) and array_key_exists('options', $value)) {
163
+ array_push($creditCardSignature[$key]['options'], 'updateExistingToken');
164
+ }
165
+ }
166
+
167
+ $signature = array(
168
+ 'id', 'company', 'email', 'fax', 'firstName',
169
+ 'lastName', 'phone', 'website', 'deviceData',
170
+ 'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce',
171
+ array('creditCard' => $creditCardSignature),
172
+ array('customFields' => array('_anyKey_')),
173
+ );
174
+ return $signature;
175
+ }
176
+
177
+
178
+ /**
179
+ * find a customer by id
180
+ *
181
+ * @access public
182
+ * @param string id customer Id
183
+ * @return object Braintree_Customer
184
+ * @throws Braintree_Exception_NotFound
185
+ */
186
+ public function find($id)
187
+ {
188
+ $this->_validateId($id);
189
+ try {
190
+ $path = $this->_config->merchantPath() . '/customers/' . $id;
191
+ $response = $this->_http->get($path);
192
+ return Braintree_Customer::factory($response['customer']);
193
+ } catch (Braintree_Exception_NotFound $e) {
194
+ throw new Braintree_Exception_NotFound(
195
+ 'customer with id ' . $id . ' not found'
196
+ );
197
+ }
198
+
199
+ }
200
+
201
+ /**
202
+ * credit a customer for the passed transaction
203
+ *
204
+ * @access public
205
+ * @param array $attribs
206
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
207
+ */
208
+ public function credit($customerId, $transactionAttribs)
209
+ {
210
+ $this->_validateId($customerId);
211
+ return Braintree_Transaction::credit(
212
+ array_merge($transactionAttribs,
213
+ array('customerId' => $customerId)
214
+ )
215
+ );
216
+ }
217
+
218
+ /**
219
+ * credit a customer, assuming validations will pass
220
+ *
221
+ * returns a Braintree_Transaction object on success
222
+ *
223
+ * @access public
224
+ * @param array $attribs
225
+ * @return object Braintree_Transaction
226
+ * @throws Braintree_Exception_ValidationError
227
+ */
228
+ public function creditNoValidate($customerId, $transactionAttribs)
229
+ {
230
+ $result = $this->credit($customerId, $transactionAttribs);
231
+ return Braintree_Util::returnObjectOrThrowException('Braintree_Transaction', $result);
232
+ }
233
+
234
+ /**
235
+ * delete a customer by id
236
+ *
237
+ * @param string $customerId
238
+ */
239
+ public function delete($customerId)
240
+ {
241
+ $this->_validateId($customerId);
242
+ $path = $this->_config->merchantPath() . '/customers/' . $customerId;
243
+ $this->_http->delete($path);
244
+ return new Braintree_Result_Successful();
245
+ }
246
+
247
+ /**
248
+ * create a new sale for a customer
249
+ *
250
+ * @param string $customerId
251
+ * @param array $transactionAttribs
252
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
253
+ * @see Braintree_Transaction::sale()
254
+ */
255
+ public function sale($customerId, $transactionAttribs)
256
+ {
257
+ $this->_validateId($customerId);
258
+ return Braintree_Transaction::sale(
259
+ array_merge($transactionAttribs,
260
+ array('customerId' => $customerId)
261
+ )
262
+ );
263
+ }
264
+
265
+ /**
266
+ * create a new sale for a customer, assuming validations will pass
267
+ *
268
+ * returns a Braintree_Transaction object on success
269
+ * @access public
270
+ * @param string $customerId
271
+ * @param array $transactionAttribs
272
+ * @return object Braintree_Transaction
273
+ * @throws Braintree_Exception_ValidationsFailed
274
+ * @see Braintree_Transaction::sale()
275
+ */
276
+ public function saleNoValidate($customerId, $transactionAttribs)
277
+ {
278
+ $result = $this->sale($customerId, $transactionAttribs);
279
+ return Braintree_Util::returnObjectOrThrowException('Braintree_Transaction', $result);
280
+ }
281
+
282
+ /**
283
+ * Returns a ResourceCollection of customers matching the search query.
284
+ *
285
+ * If <b>query</b> is a string, the search will be a basic search.
286
+ * If <b>query</b> is a hash, the search will be an advanced search.
287
+ * For more detailed information and examples, see {@link http://www.braintreepayments.com/gateway/customer-api#searching http://www.braintreepaymentsolutions.com/gateway/customer-api}
288
+ *
289
+ * @param mixed $query search query
290
+ * @param array $options options such as page number
291
+ * @return object Braintree_ResourceCollection
292
+ * @throws InvalidArgumentException
293
+ */
294
+ public function search($query)
295
+ {
296
+ $criteria = array();
297
+ foreach ($query as $term) {
298
+ $result = $term->toparam();
299
+ if(is_null($result) || empty($result)) {
300
+ throw new InvalidArgumentException('Operator must be provided');
301
+ }
302
+
303
+ $criteria[$term->name] = $term->toparam();
304
+ }
305
+
306
+ $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
307
+ $response = $this->_http->post($path, array('search' => $criteria));
308
+ $pager = array(
309
+ 'object' => $this,
310
+ 'method' => 'fetch',
311
+ 'methodArgs' => array($query)
312
+ );
313
+
314
+ return new Braintree_ResourceCollection($response, $pager);
315
+ }
316
+
317
+ /**
318
+ * updates the customer record
319
+ *
320
+ * if calling this method in static context, customerId
321
+ * is the 2nd attribute. customerId is not sent in object context.
322
+ *
323
+ * @access public
324
+ * @param array $attributes
325
+ * @param string $customerId (optional)
326
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
327
+ */
328
+ public function update($customerId, $attributes)
329
+ {
330
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
331
+ $this->_validateId($customerId);
332
+ return $this->_doUpdate(
333
+ 'put',
334
+ '/customers/' . $customerId,
335
+ array('customer' => $attributes)
336
+ );
337
+ }
338
+
339
+ /**
340
+ * update a customer record, assuming validations will pass
341
+ *
342
+ * if calling this method in static context, customerId
343
+ * is the 2nd attribute. customerId is not sent in object context.
344
+ * returns a Braintree_Customer object on success
345
+ *
346
+ * @access public
347
+ * @param array $attributes
348
+ * @param string $customerId
349
+ * @return object Braintree_Customer
350
+ * @throws Braintree_Exception_ValidationsFailed
351
+ */
352
+ public function updateNoValidate($customerId, $attributes)
353
+ {
354
+ $result = $this->update($customerId, $attributes);
355
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
356
+ }
357
+ /**
358
+ *
359
+ * @access public
360
+ * @param none
361
+ * @return string
362
+ */
363
+ public function updateCustomerUrl()
364
+ {
365
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
366
+ return $this->_config->baseUrl() . $this->_config->merchantPath() .
367
+ '/customers/all/update_via_transparent_redirect_request';
368
+ }
369
+
370
+ /**
371
+ * update a customer from a TransparentRedirect operation
372
+ *
373
+ * @access public
374
+ * @param array $attribs
375
+ * @return object
376
+ */
377
+ public function updateFromTransparentRedirect($queryString)
378
+ {
379
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
380
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
381
+ $queryString
382
+ );
383
+ return $this->_doUpdate(
384
+ 'post',
385
+ '/customers/all/confirm_transparent_redirect_request',
386
+ array('id' => $params['id'])
387
+ );
388
+ }
389
+
390
+ /* instance methods */
391
+
392
+ /**
393
+ * sets instance properties from an array of values
394
+ *
395
+ * @ignore
396
+ * @access protected
397
+ * @param array $customerAttribs array of customer data
398
+ * @return none
399
+ */
400
+ protected function _initialize($customerAttribs)
401
+ {
402
+ // set the attributes
403
+ $this->_attributes = $customerAttribs;
404
+
405
+ // map each address into its own object
406
+ $addressArray = array();
407
+ if (isset($customerAttribs['addresses'])) {
408
+
409
+ foreach ($customerAttribs['addresses'] AS $address) {
410
+ $addressArray[] = Braintree_Address::factory($address);
411
+ }
412
+ }
413
+ $this->_set('addresses', $addressArray);
414
+
415
+ // map each creditCard into its own object
416
+ $creditCardArray = array();
417
+ if (isset($customerAttribs['creditCards'])) {
418
+ foreach ($customerAttribs['creditCards'] AS $creditCard) {
419
+ $creditCardArray[] = Braintree_CreditCard::factory($creditCard);
420
+ }
421
+ }
422
+ $this->_set('creditCards', $creditCardArray);
423
+
424
+ // map each paypalAccount into its own object
425
+ $paypalAccountArray = array();
426
+ if (isset($customerAttribs['paypalAccounts'])) {
427
+ foreach ($customerAttribs['paypalAccounts'] AS $paypalAccount) {
428
+ $paypalAccountArray[] = Braintree_PayPalAccount::factory($paypalAccount);
429
+ }
430
+ }
431
+ $this->_set('paypalAccounts', $paypalAccountArray);
432
+
433
+ // map each applePayCard into its own object
434
+ $applePayCardArray = array();
435
+ if (isset($customerAttribs['applePayCards'])) {
436
+ foreach ($customerAttribs['applePayCards'] AS $applePayCard) {
437
+ $applePayCardArray[] = Braintree_applePayCard::factory($applePayCard);
438
+ }
439
+ }
440
+ $this->_set('applePayCards', $applePayCardArray);
441
+ }
442
+
443
+ /**
444
+ * returns a string representation of the customer
445
+ * @return string
446
+ */
447
+ public function __toString()
448
+ {
449
+ return __CLASS__ . '[' .
450
+ Braintree_Util::attributesToString($this->_attributes) .']';
451
+ }
452
+
453
+ /**
454
+ * returns false if comparing object is not a Braintree_Customer,
455
+ * or is a Braintree_Customer with a different id
456
+ *
457
+ * @param object $otherCust customer to compare against
458
+ * @return boolean
459
+ */
460
+ public function isEqual($otherCust)
461
+ {
462
+ return !($otherCust instanceof Braintree_Customer) ? false : $this->id === $otherCust->id;
463
+ }
464
+
465
+ /**
466
+ * returns an array containt all of the customer's payment methods
467
+ *
468
+ * @return array
469
+ */
470
+ public function paymentMethods()
471
+ {
472
+ return array_merge($this->creditCards, $this->paypalAccounts, $this->applePayCards);
473
+ }
474
+
475
+ /**
476
+ * returns the customer's default payment method
477
+ *
478
+ * @return object Braintree_CreditCard or Braintree_PayPalAccount
479
+ */
480
+ public function defaultPaymentMethod()
481
+ {
482
+ $defaultPaymentMethods = array_filter($this->paymentMethods(), 'Braintree_Customer::_defaultPaymentMethodFilter');
483
+ return current($defaultPaymentMethods);
484
+ }
485
+
486
+ public static function _defaultPaymentMethodFilter($paymentMethod)
487
+ {
488
+ return $paymentMethod->isDefault();
489
+ }
490
+
491
+ /* private class properties */
492
+
493
+ /**
494
+ * @access protected
495
+ * @var array registry of customer data
496
+ */
497
+ protected $_attributes = array(
498
+ 'addresses' => '',
499
+ 'company' => '',
500
+ 'creditCards' => '',
501
+ 'email' => '',
502
+ 'fax' => '',
503
+ 'firstName' => '',
504
+ 'id' => '',
505
+ 'lastName' => '',
506
+ 'phone' => '',
507
+ 'createdAt' => '',
508
+ 'updatedAt' => '',
509
+ 'website' => '',
510
+ );
511
+
512
+ /**
513
+ * sends the create request to the gateway
514
+ *
515
+ * @ignore
516
+ * @param string $subPath
517
+ * @param array $params
518
+ * @return mixed
519
+ */
520
+ public function _doCreate($subPath, $params)
521
+ {
522
+ $fullPath = $this->_config->merchantPath() . $subPath;
523
+ $response = $this->_http->post($fullPath, $params);
524
+
525
+ return $this->_verifyGatewayResponse($response);
526
+ }
527
+
528
+ /**
529
+ * verifies that a valid customer id is being used
530
+ * @ignore
531
+ * @param string customer id
532
+ * @throws InvalidArgumentException
533
+ */
534
+ private function _validateId($id = null) {
535
+ if (empty($id)) {
536
+ throw new InvalidArgumentException(
537
+ 'expected customer id to be set'
538
+ );
539
+ }
540
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
541
+ throw new InvalidArgumentException(
542
+ $id . ' is an invalid customer id.'
543
+ );
544
+ }
545
+ }
546
+
547
+
548
+ /* private class methods */
549
+
550
+ /**
551
+ * sends the update request to the gateway
552
+ *
553
+ * @ignore
554
+ * @param string $subPath
555
+ * @param array $params
556
+ * @return mixed
557
+ */
558
+ private function _doUpdate($httpVerb, $subPath, $params)
559
+ {
560
+ $fullPath = $this->_config->merchantPath() . $subPath;
561
+ $response = $this->_http->$httpVerb($fullPath, $params);
562
+
563
+ return $this->_verifyGatewayResponse($response);
564
+ }
565
+
566
+ /**
567
+ * generic method for validating incoming gateway responses
568
+ *
569
+ * creates a new Braintree_Customer object and encapsulates
570
+ * it inside a Braintree_Result_Successful object, or
571
+ * encapsulates a Braintree_Errors object inside a Result_Error
572
+ * alternatively, throws an Unexpected exception if the response is invalid.
573
+ *
574
+ * @ignore
575
+ * @param array $response gateway response values
576
+ * @return object Result_Successful or Result_Error
577
+ * @throws Braintree_Exception_Unexpected
578
+ */
579
+ private function _verifyGatewayResponse($response)
580
+ {
581
+ if (isset($response['customer'])) {
582
+ // return a populated instance of Braintree_Customer
583
+ return new Braintree_Result_Successful(
584
+ Braintree_Customer::factory($response['customer'])
585
+ );
586
+ } else if (isset($response['apiErrorResponse'])) {
587
+ return new Braintree_Result_Error($response['apiErrorResponse']);
588
+ } else {
589
+ throw new Braintree_Exception_Unexpected(
590
+ "Expected customer or apiErrorResponse"
591
+ );
592
+ }
593
+ }
594
+ }
lib/Braintree/CustomerSearch.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CustomerSearch
3
+ {
4
+ static function addressCountryName() { return new Braintree_TextNode('address_country_name'); }
5
+ static function addressExtendedAddress() { return new Braintree_TextNode('address_extended_address'); }
6
+ static function addressFirstName() { return new Braintree_TextNode('address_first_name'); }
7
+ static function addressLastName() { return new Braintree_TextNode('address_last_name'); }
8
+ static function addressLocality() { return new Braintree_TextNode('address_locality'); }
9
+ static function addressPostalCode() { return new Braintree_TextNode('address_postal_code'); }
10
+ static function addressRegion() { return new Braintree_TextNode('address_region'); }
11
+ static function addressStreetAddress() { return new Braintree_TextNode('address_street_address'); }
12
+ static function cardholderName() { return new Braintree_TextNode('cardholder_name'); }
13
+ static function company() { return new Braintree_TextNode('company'); }
14
+ static function email() { return new Braintree_TextNode('email'); }
15
+ static function fax() { return new Braintree_TextNode('fax'); }
16
+ static function firstName() { return new Braintree_TextNode('first_name'); }
17
+ static function id() { return new Braintree_TextNode('id'); }
18
+ static function lastName() { return new Braintree_TextNode('last_name'); }
19
+ static function paymentMethodToken() { return new Braintree_TextNode('payment_method_token'); }
20
+ static function paymentMethodTokenWithDuplicates() { return new Braintree_IsNode('payment_method_token_with_duplicates'); }
21
+ static function paypalAccountEmail() { return new Braintree_IsNode('paypal_account_email'); }
22
+ static function phone() { return new Braintree_TextNode('phone'); }
23
+ static function website() { return new Braintree_TextNode('website'); }
24
+
25
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
26
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
27
+
28
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
29
+
30
+ static function createdAt() { return new Braintree_RangeNode("created_at"); }
31
+ }
lib/Braintree/Descriptor.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class Braintree_Descriptor extends Braintree_Instance
3
+ {
4
+ }
lib/Braintree/Digest.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Digest encryption module
4
+ * Digest creates an HMAC-SHA1 hash for encrypting messages
5
+ *
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ */
8
+ class Braintree_Digest
9
+ {
10
+ public static function hexDigestSha1($key, $string)
11
+ {
12
+ if(function_exists('hash_hmac')) {
13
+ return self::_builtInHmacSha1($string, $key);
14
+ } else {
15
+ return self::_hmacSha1($string, $key);
16
+ }
17
+ }
18
+
19
+ public static function hexDigestSha256($key, $string)
20
+ {
21
+ return hash_hmac('sha256', $string, hash('sha256', $key, true));
22
+ }
23
+
24
+ public static function secureCompare($left, $right)
25
+ {
26
+ if (strlen($left) != strlen($right)) {
27
+ return false;
28
+ }
29
+
30
+ $leftBytes = unpack("C*", $left);
31
+ $rightBytes = unpack("C*", $right);
32
+
33
+ $result = 0;
34
+ for ($i = 1; $i <= count($leftBytes); $i++) {
35
+ $result = $result | ($leftBytes[$i] ^ $rightBytes[$i]);
36
+ }
37
+ return $result == 0;
38
+ }
39
+
40
+ public static function _builtInHmacSha1($message, $key)
41
+ {
42
+ return hash_hmac('sha1', $message, sha1($key, true));
43
+ }
44
+
45
+ public static function _hmacSha1($message, $key)
46
+ {
47
+ $pack = 'H40';
48
+ $keyDigest = sha1($key,true);
49
+ $innerPad = str_repeat(chr(0x36), 64);
50
+ $outerPad = str_repeat(chr(0x5C), 64);
51
+
52
+ for ($i = 0; $i < 20; $i++) {
53
+ $innerPad{$i} = $keyDigest{$i} ^ $innerPad{$i};
54
+ $outerPad{$i} = $keyDigest{$i} ^ $outerPad{$i};
55
+ }
56
+
57
+ return sha1($outerPad.pack($pack, sha1($innerPad.$message)));
58
+ }
59
+ }
lib/Braintree/Disbursement.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ final class Braintree_Disbursement extends Braintree
3
+ {
4
+ private $_merchantAccount;
5
+
6
+ protected function _initialize($disbursementAttribs)
7
+ {
8
+ $this->_attributes = $disbursementAttribs;
9
+ $this->merchantAccountDetails = $disbursementAttribs['merchantAccount'];
10
+
11
+ if (isset($disbursementAttribs['merchantAccount'])) {
12
+ $this->_set('merchantAccount',
13
+ Braintree_MerchantAccount::factory($disbursementAttribs['merchantAccount'])
14
+ );
15
+ }
16
+ }
17
+
18
+ public function transactions()
19
+ {
20
+ $collection = Braintree_Transaction::search(array(
21
+ Braintree_TransactionSearch::ids()->in($this->transactionIds)
22
+ ));
23
+
24
+ return $collection;
25
+ }
26
+
27
+ public static function factory($attributes)
28
+ {
29
+ $instance = new self();
30
+ $instance->_initialize($attributes);
31
+ return $instance;
32
+ }
33
+
34
+ public function __toString()
35
+ {
36
+ $display = array(
37
+ 'id', 'merchantAccountDetails', 'exceptionMessage', 'amount',
38
+ 'disbursementDate', 'followUpAction', 'retry', 'success',
39
+ 'transactionIds'
40
+ );
41
+
42
+ $displayAttributes = array();
43
+ foreach ($display AS $attrib) {
44
+ $displayAttributes[$attrib] = $this->$attrib;
45
+ }
46
+ return __CLASS__ . '[' .
47
+ Braintree_Util::attributesToString($displayAttributes) .']';
48
+ }
49
+ }
lib/Braintree/DisbursementDetails.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Disbursement details from a transaction
4
+ * Creates an instance of DisbursementDetails as returned from a transaction
5
+ *
6
+ *
7
+ * @package Braintree
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ *
10
+ * @property-read string $settlementAmount
11
+ * @property-read string $settlementCurrencyIsoCode
12
+ * @property-read string $settlementCurrencyExchangeRate
13
+ * @property-read string $fundsHeld
14
+ * @property-read string $success
15
+ * @property-read string $disbursementDate
16
+ * @uses Braintree_Instance inherits methods
17
+ */
18
+ class Braintree_DisbursementDetails extends Braintree_Instance
19
+ {
20
+ protected $_attributes = array();
21
+
22
+ function isValid() {
23
+ return !is_null($this->disbursementDate);
24
+ }
25
+ }
lib/Braintree/Discount.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Discount extends Braintree_Modification
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self();
7
+ $instance->_initialize($attributes);
8
+ return $instance;
9
+ }
10
+
11
+
12
+ // static methods redirecting to gateway
13
+
14
+ public static function all()
15
+ {
16
+ return Braintree_Configuration::gateway()->discount()->all();
17
+ }
18
+ }
lib/Braintree/DiscountGateway.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_DiscountGateway
3
+ {
4
+ private $_gateway;
5
+ private $_config;
6
+ private $_http;
7
+
8
+ public function __construct($gateway)
9
+ {
10
+ $this->_gateway = $gateway;
11
+ $this->_config = $gateway->config;
12
+ $this->_http = new Braintree_Http($gateway->config);
13
+ }
14
+
15
+ public function all()
16
+ {
17
+ $path = $this->_config->merchantPath() . '/discounts';
18
+ $response = $this->_http->get($path);
19
+
20
+ $discounts = array("discount" => $response['discounts']);
21
+
22
+ return Braintree_Util::extractAttributeAsArray(
23
+ $discounts,
24
+ 'discount'
25
+ );
26
+ }
27
+ }
lib/Braintree/Dispute.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Creates an instance of Dispute as returned from a transaction
4
+ *
5
+ *
6
+ * @package Braintree
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ *
9
+ * @property-read string $amount
10
+ * @property-read string $currencyIsoCode
11
+ * @property-read date $receivedDate
12
+ * @property-read string $reason
13
+ * @property-read string $status
14
+ * @property-read string $disbursementDate
15
+ * @property-read object $transactionDetails
16
+ */
17
+ final class Braintree_Dispute extends Braintree
18
+ {
19
+ protected $_attributes = array();
20
+
21
+ /* Dispute Status */
22
+ const OPEN = 'open';
23
+ const WON = 'won';
24
+ const LOST = 'lost';
25
+
26
+ /* deprecated; for backwards compatibilty */
27
+ const Open = 'open';
28
+
29
+ /* Dispute Reason */
30
+ const CANCELLED_RECURRING_TRANSACTION = "cancelled_recurring_transaction";
31
+ const CREDIT_NOT_PROCESSED = "credit_not_processed";
32
+ const DUPLICATE = "duplicate";
33
+ const FRAUD = "fraud";
34
+ const GENERAL = "general";
35
+ const INVALID_ACCOUNT = "invalid_account";
36
+ const NOT_RECOGNIZED = "not_recognized";
37
+ const PRODUCT_NOT_RECEIVED = "product_not_received";
38
+ const PRODUCT_UNSATISFACTORY = "product_unsatisfactory";
39
+ const TRANSACTION_AMOUNT_DIFFERS = "transaction_amount_differs";
40
+ const RETRIEVAL = "retrieval";
41
+
42
+
43
+ protected function _initialize($disputeAttribs)
44
+ {
45
+ $this->_attributes = $disputeAttribs;
46
+
47
+ if (isset($disputeAttribs['transaction'])) {
48
+ $this->_set('transactionDetails',
49
+ new Braintree_Dispute_TransactionDetails($disputeAttribs['transaction'])
50
+ );
51
+ }
52
+ }
53
+
54
+ public static function factory($attributes)
55
+ {
56
+ $instance = new self();
57
+ $instance->_initialize($attributes);
58
+ return $instance;
59
+ }
60
+
61
+ public function __toString()
62
+ {
63
+ $display = array(
64
+ 'amount', 'reason', 'status',
65
+ 'replyByDate', 'receivedDate', 'currencyIsoCode'
66
+ );
67
+
68
+ $displayAttributes = array();
69
+ foreach ($display AS $attrib) {
70
+ $displayAttributes[$attrib] = $this->$attrib;
71
+ }
72
+ return __CLASS__ . '[' .
73
+ Braintree_Util::attributesToString($displayAttributes) .']';
74
+ }
75
+ }
lib/Braintree/Dispute/TransactionDetails.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Transaction details for a dispute
4
+ *
5
+ * @package Braintree
6
+ * @copyright 2010 Braintree Payment Solutions
7
+ */
8
+
9
+ /**
10
+ * Creates an instance of DisbursementDetails as returned from a transaction
11
+ *
12
+ *
13
+ * @package Braintree
14
+ * @copyright 2010 Braintree Payment Solutions
15
+ *
16
+ * @property-read string $amount
17
+ * @property-read string $id
18
+ * @uses Braintree_Instance inherits methods
19
+ */
20
+ class Braintree_Dispute_TransactionDetails extends Braintree_Instance
21
+ {
22
+ }
lib/Braintree/EqualityNode.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_EqualityNode extends Braintree_IsNode
4
+ {
5
+ function isNot($value)
6
+ {
7
+ $this->searchTerms['is_not'] = strval($value);
8
+ return $this;
9
+ }
10
+ }
lib/Braintree/Error/Codes.php ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Validation Error codes and messages
5
+ *
6
+ * ErrorCodes class provides constants for validation errors.
7
+ * The constants should be used to check for a specific validation
8
+ * error in a ValidationErrorCollection.
9
+ * The error messages returned from the server may change;
10
+ * but the codes will remain the same.
11
+ *
12
+ * @package Braintree
13
+ * @subpackage Errors
14
+ * @category Validation
15
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
16
+ */
17
+ class Braintree_Error_Codes
18
+ {
19
+ const ADDRESS_CANNOT_BE_BLANK = '81801';
20
+ const ADDRESS_COMPANY_IS_TOO_LONG = '81802';
21
+ const ADDRESS_COUNTRY_CODE_ALPHA2_IS_NOT_ACCEPTED = '91814';
22
+ const ADDRESS_COUNTRY_CODE_ALPHA3_IS_NOT_ACCEPTED = '91816';
23
+ const ADDRESS_COUNTRY_CODE_NUMERIC_IS_NOT_ACCEPTED = '91817';
24
+ const ADDRESS_COUNTRY_NAME_IS_NOT_ACCEPTED = '91803';
25
+ const ADDRESS_EXTENDED_ADDRESS_IS_TOO_LONG = '81804';
26
+ const ADDRESS_FIRST_NAME_IS_TOO_LONG = '81805';
27
+ const ADDRESS_INCONSISTENT_COUNTRY = '91815';
28
+ const ADDRESS_LAST_NAME_IS_TOO_LONG = '81806';
29
+ const ADDRESS_LOCALITY_IS_TOO_LONG = '81807';
30
+ const ADDRESS_POSTAL_CODE_INVALID_CHARACTERS = '81813';
31
+ const ADDRESS_POSTAL_CODE_IS_REQUIRED = '81808';
32
+ const ADDRESS_POSTAL_CODE_IS_TOO_LONG = '81809';
33
+ const ADDRESS_REGION_IS_TOO_LONG = '81810';
34
+ const ADDRESS_STREET_ADDRESS_IS_REQUIRED = '81811';
35
+ const ADDRESS_STREET_ADDRESS_IS_TOO_LONG = '81812';
36
+ const ADDRESS_TOO_MANY_ADDRESSES_PER_CUSTOMER = '91818';
37
+ const ADDRESS_COMPANY_IS_INVALID = '91821';
38
+ const ADDRESS_REGION_IS_INVALID = '91825';
39
+ const ADDRESS_POSTAL_CODE_IS_INVALID = '91826';
40
+ const ADDRESS_LAST_NAME_IS_INVALID = '91820';
41
+ const ADDRESS_EXTENDED_ADDRESS_IS_INVALID = '91823';
42
+ const ADDRESS_STREET_ADDRESS_IS_INVALID = '91822';
43
+ const ADDRESS_LOCALITY_IS_INVALID = '91824';
44
+ const ADDRESS_FIRST_NAME_IS_INVALID = '91819';
45
+
46
+ const APPLE_PAY_CARDS_ARE_NOT_ACCEPTED = "83501";
47
+ const APPLE_PAY_CUSTOMER_ID_IS_REQUIRED_FOR_VAULTING = "83502";
48
+ const APPLE_PAY_TOKEN_IS_IN_USE = "93503";
49
+ const APPLE_PAY_PAYMENT_METHOD_NONCE_CONSUMED = "93504";
50
+ const APPLE_PAY_PAYMENT_METHOD_NONCE_UNKNOWN = "93505";
51
+ const APPLE_PAY_PAYMENT_METHOD_NONCE_UNLOCKED = "93506";
52
+ const APPLE_PAY_PAYMENT_METHOD_NONCE_CARD_TYPE_IS_NOT_ACCEPTED = "83518";
53
+ const APPLE_PAY_CANNOT_UPDATE_APPLE_PAY_CARD_USING_PAYMENT_METHOD_NONCE = "93507";
54
+ const APPLE_PAY_NUMBER_IS_REQUIRED = "93508";
55
+ const APPLE_PAY_EXPIRATION_MONTH_IS_REQUIRED = "93509";
56
+ const APPLE_PAY_EXPIRATION_YEAR_IS_REQUIRED = "93510";
57
+ const APPLE_PAY_CRYPTOGRAM_IS_REQUIRED = "93511";
58
+ const APPLE_PAY_DECRYPTION_FAILED = "83512";
59
+ const APPLE_PAY_DISABLED = "93513";
60
+ const APPLE_PAY_MERCHANT_NOT_CONFIGURED = "93514";
61
+ const APPLE_PAY_MERCHANT_KEYS_ALREADY_CONFIGURED = "93515";
62
+ const APPLE_PAY_MERCHANT_KEYS_NOT_CONFIGURED = "93516";
63
+ const APPLE_PAY_CERTIFICATE_INVALID = "93517";
64
+ const APPLE_PAY_CERTIFICATE_MISMATCH = '93519';
65
+ const APPLE_PAY_INVALID_TOKEN = '83520';
66
+ const APPLE_PAY_PRIVATE_KEY_MISMATCH = '93521';
67
+ const APPLE_PAY_KEY_MISMATCH_STORING_CERTIFICATE = '93522';
68
+
69
+ const AUTHORIZATION_FINGERPRINT_INVALID_CREATED_AT = '93204';
70
+ const AUTHORIZATION_FINGERPRINT_INVALID_FORMAT = '93202';
71
+ const AUTHORIZATION_FINGERPRINT_INVALID_PUBLIC_KEY = '93205';
72
+ const AUTHORIZATION_FINGERPRINT_INVALID_SIGNATURE = '93206';
73
+ const AUTHORIZATION_FINGERPRINT_MISSING_FINGERPRINT = '93201';
74
+ const AUTHORIZATION_FINGERPRINT_OPTIONS_NOT_ALLOWED_WITHOUT_CUSTOMER = '93207';
75
+ const AUTHORIZATION_FINGERPRINT_SIGNATURE_REVOKED = '93203';
76
+
77
+ const CLIENT_TOKEN_CUSTOMER_DOES_NOT_EXIST = '92804';
78
+ const CLIENT_TOKEN_FAIL_ON_DUPLICATE_PAYMENT_METHOD_REQUIRES_CUSTOMER_ID = '92803';
79
+ const CLIENT_TOKEN_MAKE_DEFAULT_REQUIRES_CUSTOMER_ID = '92801';
80
+ const CLIENT_TOKEN_PROXY_MERCHANT_DOES_NOT_EXIST = '92805';
81
+ const CLIENT_TOKEN_UNSUPPORTED_VERSION = '92806';
82
+ const CLIENT_TOKEN_VERIFY_CARD_REQUIRES_CUSTOMER_ID = '92802';
83
+ const CLIENT_TOKEN_MERCHANT_ACCOUNT_DOES_NOT_EXIST = '92807';
84
+
85
+ const CREDIT_CARD_BILLING_ADDRESS_CONFLICT = '91701';
86
+ const CREDIT_CARD_BILLING_ADDRESS_ID_IS_INVALID = '91702';
87
+ const CREDIT_CARD_CANNOT_UPDATE_CARD_USING_PAYMENT_METHOD_NONCE = '91735';
88
+ const CREDIT_CARD_CARDHOLDER_NAME_IS_TOO_LONG = '81723';
89
+ const CREDIT_CARD_CREDIT_CARD_TYPE_IS_NOT_ACCEPTED = '81703';
90
+ const CREDIT_CARD_CREDIT_CARD_TYPE_IS_NOT_ACCEPTED_BY_SUBSCRIPTION_MERCHANT_ACCOUNT = '81718';
91
+ const CREDIT_CARD_CUSTOMER_ID_IS_INVALID = '91705';
92
+ const CREDIT_CARD_CUSTOMER_ID_IS_REQUIRED = '91704';
93
+ const CREDIT_CARD_CVV_IS_INVALID = '81707';
94
+ const CREDIT_CARD_CVV_IS_REQUIRED = '81706';
95
+ const CREDIT_CARD_CVV_VERIFICATION_FAILED = '81736';
96
+ const CREDIT_CARD_DUPLICATE_CARD_EXISTS = '81724';
97
+ const CREDIT_CARD_EXPIRATION_DATE_CONFLICT = '91708';
98
+ const CREDIT_CARD_EXPIRATION_DATE_IS_INVALID = '81710';
99
+ const CREDIT_CARD_EXPIRATION_DATE_IS_REQUIRED = '81709';
100
+ const CREDIT_CARD_EXPIRATION_DATE_YEAR_IS_INVALID = '81711';
101
+ const CREDIT_CARD_EXPIRATION_MONTH_IS_INVALID = '81712';
102
+ const CREDIT_CARD_EXPIRATION_YEAR_IS_INVALID = '81713';
103
+ const CREDIT_CARD_INVALID_VENMO_SDK_PAYMENT_METHOD_CODE = '91727';
104
+ const CREDIT_CARD_NUMBER_INVALID_LENGTH = '81716';
105
+ const CREDIT_CARD_NUMBER_IS_INVALID = '81715';
106
+ const CREDIT_CARD_NUMBER_IS_REQUIRED = '81714';
107
+ const CREDIT_CARD_NUMBER_LENGTH_IS_INVALID = '81716';
108
+ const CREDIT_CARD_NUMBER_MUST_BE_TEST_NUMBER = '81717';
109
+ const CREDIT_CARD_OPTIONS_UPDATE_EXISTING_TOKEN_IS_INVALID = '91723';
110
+ const CREDIT_CARD_OPTIONS_UPDATE_EXISTING_TOKEN_NOT_ALLOWED = '91729';
111
+ const CREDIT_CARD_OPTIONS_VERIFICATION_MERCHANT_ACCOUNT_ID_IS_INVALID = '91728';
112
+ const CREDIT_CARD_OPTIONS_VERIFICATION_AMOUNT_CANNOT_BE_NEGATIVE = '91739';
113
+ const CREDIT_CARD_OPTIONS_VERIFICATION_AMOUNT_FORMAT_IS_INVALID = '91740';
114
+ const CREDIT_CARD_OPTIONS_VERIFICATION_AMOUNT_NOT_SUPPORTED_BY_PROCESSOR = '91741';
115
+ const CREDIT_CARD_PAYMENT_METHOD_CONFLICT = '81725';
116
+ const CREDIT_CARD_PAYMENT_METHOD_NONCE_CARD_TYPE_IS_NOT_ACCEPTED = '91734';
117
+ const CREDIT_CARD_PAYMENT_METHOD_NONCE_CONSUMED = '91731';
118
+ const CREDIT_CARD_PAYMENT_METHOD_NONCE_LOCKED = '91733';
119
+ const CREDIT_CARD_PAYMENT_METHOD_NONCE_UNKNOWN = '91732';
120
+ const CREDIT_CARD_PAYMENT_METHOD_IS_NOT_A_CREDIT_CARD = '91738';
121
+ const CREDIT_CARD_POSTAL_CODE_VERIFICATION_FAILED = '81737';
122
+ const CREDIT_CARD_TOKEN_FORMAT_IS_INVALID = '91718';
123
+ const CREDIT_CARD_TOKEN_INVALID = '91718';
124
+ const CREDIT_CARD_TOKEN_IS_IN_USE = '91719';
125
+ const CREDIT_CARD_TOKEN_IS_NOT_ALLOWED = '91721';
126
+ const CREDIT_CARD_TOKEN_IS_REQUIRED = '91722';
127
+ const CREDIT_CARD_TOKEN_IS_TOO_LONG = '91720';
128
+ const CREDIT_CARD_VENMO_SDK_PAYMENT_METHOD_CODE_CARD_TYPE_IS_NOT_ACCEPTED = '91726';
129
+ const CREDIT_CARD_VERIFICATION_NOT_SUPPORTED_ON_THIS_MERCHANT_ACCOUNT = '91730';
130
+
131
+ const CUSTOMER_COMPANY_IS_TOO_LONG = '81601';
132
+ const CUSTOMER_CUSTOM_FIELD_IS_INVALID = '91602';
133
+ const CUSTOMER_CUSTOM_FIELD_IS_TOO_LONG = '81603';
134
+ const CUSTOMER_EMAIL_IS_INVALID = '81604';
135
+ const CUSTOMER_EMAIL_FORMAT_IS_INVALID = '81604';
136
+ const CUSTOMER_EMAIL_IS_REQUIRED = '81606';
137
+ const CUSTOMER_EMAIL_IS_TOO_LONG = '81605';
138
+ const CUSTOMER_FAX_IS_TOO_LONG = '81607';
139
+ const CUSTOMER_FIRST_NAME_IS_TOO_LONG = '81608';
140
+ const CUSTOMER_ID_IS_INVAILD = '91610'; //Deprecated
141
+ const CUSTOMER_ID_IS_INVALID = '91610';
142
+ const CUSTOMER_ID_IS_IN_USE = '91609';
143
+ const CUSTOMER_ID_IS_NOT_ALLOWED = '91611';
144
+ const CUSTOMER_ID_IS_REQUIRED = '91613';
145
+ const CUSTOMER_ID_IS_TOO_LONG = '91612';
146
+ const CUSTOMER_LAST_NAME_IS_TOO_LONG = '81613';
147
+ const CUSTOMER_PHONE_IS_TOO_LONG = '81614';
148
+ const CUSTOMER_WEBSITE_IS_INVALID = '81616';
149
+ const CUSTOMER_WEBSITE_FORMAT_IS_INVALID = '81616';
150
+ const CUSTOMER_WEBSITE_IS_TOO_LONG = '81615';
151
+
152
+ const DESCRIPTOR_NAME_FORMAT_IS_INVALID = '92201';
153
+ const DESCRIPTOR_PHONE_FORMAT_IS_INVALID = '92202';
154
+ const DESCRIPTOR_INTERNATIONAL_NAME_FORMAT_IS_INVALID = '92204';
155
+ const DESCRIPTOR_DYNAMIC_DESCRIPTORS_DISABLED = '92203';
156
+ const DESCRIPTOR_INTERNATIONAL_PHONE_FORMAT_IS_INVALID = '92205';
157
+ const DESCRIPTOR_URL_FORMAT_IS_INVALID = '92206';
158
+
159
+ const INDUSTRY_DATA_INDUSTRY_TYPE_IS_INVALID = '93401';
160
+ const INDUSTRY_DATA_LODGING_EMPTY_DATA = '93402';
161
+ const INDUSTRY_DATA_LODGING_FOLIO_NUMBER_IS_INVALID = '93403';
162
+ const INDUSTRY_DATA_LODGING_CHECK_IN_DATE_IS_INVALID = '93404';
163
+ const INDUSTRY_DATA_LODGING_CHECK_OUT_DATE_IS_INVALID = '93405';
164
+ const INDUSTRY_DATA_LODGING_CHECK_OUT_DATE_MUST_FOLLOW_CHECK_IN_DATE = '93406';
165
+ const INDUSTRY_DATA_LODGING_UNKNOWN_DATA_FIELD = '93407';
166
+ const INDUSTRY_DATA_TRAVEL_CRUISE_EMPTY_DATA = "93408";
167
+ const INDUSTRY_DATA_TRAVEL_CRUISE_UNKNOWN_DATA_FIELD = "93409";
168
+ const INDUSTRY_DATA_TRAVEL_CRUISE_TRAVEL_PACKAGE_IS_INVALID = "93410";
169
+ const INDUSTRY_DATA_TRAVEL_CRUISE_DEPARTURE_DATE_IS_INVALID = "93411";
170
+ const INDUSTRY_DATA_TRAVEL_CRUISE_LODGING_CHECK_IN_DATE_IS_INVALID = "93412";
171
+ const INDUSTRY_DATA_TRAVEL_CRUISE_LODGING_CHECK_OUT_DATE_IS_INVALID = "93413";
172
+
173
+ const MERCHANT_ACCOUNT_ID_FORMAT_IS_INVALID = '82603';
174
+ const MERCHANT_ACCOUNT_ID_IS_IN_USE = '82604';
175
+ const MERCHANT_ACCOUNT_ID_IS_NOT_ALLOWED = '82605';
176
+ const MERCHANT_ACCOUNT_ID_IS_TOO_LONG = '82602';
177
+ const MERCHANT_ACCOUNT_MASTER_MERCHANT_ACCOUNT_ID_IS_INVALID = '82607';
178
+ const MERCHANT_ACCOUNT_MASTER_MERCHANT_ACCOUNT_ID_IS_REQUIRED = '82606';
179
+ const MERCHANT_ACCOUNT_MASTER_MERCHANT_ACCOUNT_MUST_BE_ACTIVE = '82608';
180
+ const MERCHANT_ACCOUNT_TOS_ACCEPTED_IS_REQUIRED = '82610';
181
+ const MERCHANT_ACCOUNT_CANNOT_BE_UPDATED = '82674';
182
+ const MERCHANT_ACCOUNT_DECLINED = '82626';
183
+ const MERCHANT_ACCOUNT_DECLINED_MASTER_CARD_MATCH = '82622';
184
+ const MERCHANT_ACCOUNT_DECLINED_OFAC = '82621';
185
+ const MERCHANT_ACCOUNT_DECLINED_FAILED_KYC = '82623';
186
+ const MERCHANT_ACCOUNT_DECLINED_SSN_INVALID = '82624';
187
+ const MERCHANT_ACCOUNT_DECLINED_SSN_MATCHES_DECEASED = '82625';
188
+ const MERCHANT_ACCOUNT_ID_CANNOT_BE_UPDATED = '82675';
189
+ const MERCHANT_ACCOUNT_MASTER_MERCHANT_ACCOUNT_ID_CANNOT_BE_UPDATED = '82676';
190
+
191
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ACCOUNT_NUMBER_IS_REQUIRED = '82614';
192
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_COMPANY_NAME_IS_INVALID = '82631';
193
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_COMPANY_NAME_IS_REQUIRED_WITH_TAX_ID = '82633';
194
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DATE_OF_BIRTH_IS_REQUIRED = '82612';
195
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED = '82626'; // Keep for backwards compatibility
196
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED_MASTER_CARD_MATCH = '82622'; // Keep for backwards compatibility
197
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED_OFAC = '82621'; // Keep for backwards compatibility
198
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED_FAILED_KYC = '82623'; // Keep for backwards compatibility
199
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED_SSN_INVALID = '82624'; // Keep for backwards compatibility
200
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DECLINED_SSN_MATCHES_DECEASED = '82625'; // Keep for backwards compatibility
201
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_EMAIL_ADDRESS_IS_INVALID = '82616';
202
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_FIRST_NAME_IS_INVALID = '82627';
203
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_FIRST_NAME_IS_REQUIRED = '82609';
204
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_LAST_NAME_IS_INVALID = '82628';
205
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_LAST_NAME_IS_REQUIRED = '82611';
206
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_PHONE_IS_INVALID = '82636';
207
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ROUTING_NUMBER_IS_INVALID = '82635';
208
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ROUTING_NUMBER_IS_REQUIRED = '82613';
209
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_SSN_IS_INVALID = '82615';
210
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_TAX_ID_IS_INVALID = '82632';
211
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_TAX_ID_IS_REQUIRED_WITH_COMPANY_NAME = '82634';
212
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_DATE_OF_BIRTH_IS_INVALID = '82663';
213
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_REGION_IS_INVALID = '82664';
214
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_EMAIL_ADDRESS_IS_REQUIRED = '82665';
215
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ACCOUNT_NUMBER_IS_INVALID = '82670';
216
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_TAX_ID_MUST_BE_BLANK = '82673';
217
+
218
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_LOCALITY_IS_REQUIRED = '82618';
219
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_POSTAL_CODE_IS_INVALID = '82630';
220
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_POSTAL_CODE_IS_REQUIRED = '82619';
221
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_REGION_IS_REQUIRED = '82620';
222
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_STREET_ADDRESS_IS_INVALID = '82629';
223
+ const MERCHANT_ACCOUNT_APPLICANT_DETAILS_ADDRESS_STREET_ADDRESS_IS_REQUIRED = '82617';
224
+
225
+ const MERCHANT_ACCOUNT_BUSINESS_DBA_NAME_IS_INVALID = '82646';
226
+ const MERCHANT_ACCOUNT_BUSINESS_TAX_ID_IS_INVALID = '82647';
227
+ const MERCHANT_ACCOUNT_BUSINESS_TAX_ID_IS_REQUIRED_WITH_LEGAL_NAME = '82648';
228
+ const MERCHANT_ACCOUNT_BUSINESS_LEGAL_NAME_IS_REQUIRED_WITH_TAX_ID = '82669';
229
+ const MERCHANT_ACCOUNT_BUSINESS_TAX_ID_MUST_BE_BLANK = '82672';
230
+ const MERCHANT_ACCOUNT_BUSINESS_LEGAL_NAME_IS_INVALID = '82677';
231
+ const MERCHANT_ACCOUNT_BUSINESS_ADDRESS_REGION_IS_INVALID = '82684';
232
+ const MERCHANT_ACCOUNT_BUSINESS_ADDRESS_STREET_ADDRESS_IS_INVALID = '82685';
233
+ const MERCHANT_ACCOUNT_BUSINESS_ADDRESS_POSTAL_CODE_IS_INVALID = '82686';
234
+
235
+ const MERCHANT_ACCOUNT_INDIVIDUAL_FIRST_NAME_IS_REQUIRED = '82637';
236
+ const MERCHANT_ACCOUNT_INDIVIDUAL_LAST_NAME_IS_REQUIRED = '82638';
237
+ const MERCHANT_ACCOUNT_INDIVIDUAL_DATE_OF_BIRTH_IS_REQUIRED = '82639';
238
+ const MERCHANT_ACCOUNT_INDIVIDUAL_SSN_IS_INVALID = '82642';
239
+ const MERCHANT_ACCOUNT_INDIVIDUAL_EMAIL_IS_INVALID = '82643';
240
+ const MERCHANT_ACCOUNT_INDIVIDUAL_FIRST_NAME_IS_INVALID = '82644';
241
+ const MERCHANT_ACCOUNT_INDIVIDUAL_LAST_NAME_IS_INVALID = '82645';
242
+ const MERCHANT_ACCOUNT_INDIVIDUAL_PHONE_IS_INVALID = '82656';
243
+ const MERCHANT_ACCOUNT_INDIVIDUAL_DATE_OF_BIRTH_IS_INVALID = '82666';
244
+ const MERCHANT_ACCOUNT_INDIVIDUAL_EMAIL_IS_REQUIRED = '82667';
245
+
246
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_STREET_ADDRESS_IS_REQUIRED = '82657';
247
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_LOCALITY_IS_REQUIRED = '82658';
248
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_POSTAL_CODE_IS_REQUIRED = '82659';
249
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_REGION_IS_REQUIRED = '82660';
250
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_STREET_ADDRESS_IS_INVALID = '82661';
251
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_POSTAL_CODE_IS_INVALID = '82662';
252
+ const MERCHANT_ACCOUNT_INDIVIDUAL_ADDRESS_REGION_IS_INVALID = '82668';
253
+
254
+ const MERCHANT_ACCOUNT_FUNDING_ROUTING_NUMBER_IS_REQUIRED = '82640';
255
+ const MERCHANT_ACCOUNT_FUNDING_ACCOUNT_NUMBER_IS_REQUIRED = '82641';
256
+ const MERCHANT_ACCOUNT_FUNDING_ROUTING_NUMBER_IS_INVALID = '82649';
257
+ const MERCHANT_ACCOUNT_FUNDING_ACCOUNT_NUMBER_IS_INVALID = '82671';
258
+ const MERCHANT_ACCOUNT_FUNDING_DESTINATION_IS_REQUIRED = '82678';
259
+ const MERCHANT_ACCOUNT_FUNDING_DESTINATION_IS_INVALID = '82679';
260
+ const MERCHANT_ACCOUNT_FUNDING_EMAIL_IS_REQUIRED = '82680';
261
+ const MERCHANT_ACCOUNT_FUNDING_EMAIL_IS_INVALID = '82681';
262
+ const MERCHANT_ACCOUNT_FUNDING_MOBILE_PHONE_IS_REQUIRED = '82682';
263
+ const MERCHANT_ACCOUNT_FUNDING_MOBILE_PHONE_IS_INVALID = '82683';
264
+
265
+ const PAYMENT_METHOD_CANNOT_FORWARD_PAYMENT_METHOD_TYPE = '93106';
266
+ const PAYMENT_METHOD_CUSTOMER_ID_IS_INVALID = '93105';
267
+ const PAYMENT_METHOD_CUSTOMER_ID_IS_REQUIRED = '93104';
268
+ const PAYMENT_METHOD_NONCE_IS_INVALID = '93102';
269
+ const PAYMENT_METHOD_NONCE_IS_REQUIRED = '93103';
270
+ const PAYMENT_METHOD_PAYMENT_METHOD_NONCE_CONSUMED = '93107';
271
+ const PAYMENT_METHOD_PAYMENT_METHOD_NONCE_UNKNOWN = '93108';
272
+ const PAYMENT_METHOD_PAYMENT_METHOD_NONCE_LOCKED = '93109';
273
+ const PAYMENT_METHOD_PAYMENT_METHOD_PARAMS_ARE_REQUIRED = '93101';
274
+
275
+ const PAYPAL_ACCOUNT_CANNOT_HAVE_BOTH_ACCESS_TOKEN_AND_CONSENT_CODE = '82903';
276
+ const PAYPAL_ACCOUNT_CANNOT_VAULT_ONE_TIME_USE_PAYPAL_ACCOUNT = '82902';
277
+ const PAYPAL_ACCOUNT_CONSENT_CODE_OR_ACCESS_TOKEN_IS_REQUIRED = '82901';
278
+ const PAYPAL_ACCOUNT_CUSTOMER_ID_IS_REQUIRED_FOR_VAULTING = '82905';
279
+ const PAYPAL_ACCOUNT_PAYMENT_METHOD_NONCE_CONSUMED = '92907';
280
+ const PAYPAL_ACCOUNT_PAYMENT_METHOD_NONCE_LOCKED = '92909';
281
+ const PAYPAL_ACCOUNT_PAYMENT_METHOD_NONCE_UNKNOWN = '92908';
282
+ const PAYPAL_ACCOUNT_PAYPAL_ACCOUNTS_ARE_NOT_ACCEPTED = '82904';
283
+ const PAYPAL_ACCOUNT_PAYPAL_COMMUNICATION_ERROR = '92910';
284
+ const PAYPAL_ACCOUNT_TOKEN_IS_IN_USE = '92906';
285
+ const PAYPAL_ACCOUNT_AUTH_EXPIRED = '92911';
286
+ const PAYPAL_ACCOUNT_CANNOT_HAVE_FUNDING_SOURCE_WITHOUT_ACCESS_TOKEN = '92912';
287
+ const PAYPAL_ACCOUNT_INVALID_FUNDING_SOURCE_SELECTION = '92913';
288
+ const PAYPAL_ACCOUNT_CANNOT_UPDATE_PAYPAL_ACCOUNT_USING_PAYMENT_METHOD_NONCE = '92914';
289
+
290
+ const SEPA_BANK_ACCOUNT_ACCOUNT_HOLDER_NAME_IS_REQUIRED = '93003';
291
+ const SEPA_BANK_ACCOUNT_BIC_IS_REQUIRED = '93002';
292
+ const SEPA_BANK_ACCOUNT_IBAN_IS_REQUIRED = '93001';
293
+
294
+ const SEPA_MANDATE_ACCOUNT_HOLDER_NAME_IS_REQUIRED = '83301';
295
+ const SEPA_MANDATE_BIC_INVALID_CHARACTER = '83306';
296
+ const SEPA_MANDATE_BIC_IS_REQUIRED = '83302';
297
+ const SEPA_MANDATE_BIC_LENGTH_IS_INVALID = '83307';
298
+ const SEPA_MANDATE_BIC_UNSUPPORTED_COUNTRY = '83308';
299
+ const SEPA_MANDATE_BILLING_ADDRESS_CONFLICT = '93311';
300
+ const SEPA_MANDATE_BILLING_ADDRESS_ID_IS_INVALID = '93312';
301
+ const SEPA_MANDATE_IBAN_INVALID_CHARACTER = '83305';
302
+ const SEPA_MANDATE_IBAN_INVALID_FORMAT = '83310';
303
+ const SEPA_MANDATE_IBAN_IS_REQUIRED = '83303';
304
+ const SEPA_MANDATE_IBAN_UNSUPPORTED_COUNTRY = '83309';
305
+ const SEPA_MANDATE_TYPE_IS_REQUIRED = '93304';
306
+ const SEPA_MANDATE_TYPE_IS_INVALID = '93313';
307
+
308
+ const SETTLEMENT_BATCH_SUMMARY_SETTLEMENT_DATE_IS_INVALID = '82302';
309
+ const SETTLEMENT_BATCH_SUMMARY_SETTLEMENT_DATE_IS_REQUIRED = '82301';
310
+ const SETTLEMENT_BATCH_SUMMARY_CUSTOM_FIELD_IS_INVALID = '82303';
311
+
312
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_CANNOT_BE_UPDATED = '91918';
313
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_IS_INVALID = '91914';
314
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_MUST_BE_NUMERIC = '91913';
315
+ const SUBSCRIPTION_CANNOT_ADD_DUPLICATE_ADDON_OR_DISCOUNT = '91911';
316
+ const SUBSCRIPTION_CANNOT_EDIT_CANCELED_SUBSCRIPTION = '81901';
317
+ const SUBSCRIPTION_CANNOT_EDIT_EXPIRED_SUBSCRIPTION = '81910';
318
+ const SUBSCRIPTION_CANNOT_EDIT_PRICE_CHANGING_FIELDS_ON_PAST_DUE_SUBSCRIPTION = '91920';
319
+ const SUBSCRIPTION_FIRST_BILLING_DATE_CANNOT_BE_IN_THE_PAST = '91916';
320
+ const SUBSCRIPTION_FIRST_BILLING_DATE_CANNOT_BE_UPDATED = '91919';
321
+ const SUBSCRIPTION_FIRST_BILLING_DATE_IS_INVALID = '91915';
322
+ const SUBSCRIPTION_ID_IS_IN_USE = '81902';
323
+ const SUBSCRIPTION_INCONSISTENT_NUMBER_OF_BILLING_CYCLES = '91908';
324
+ const SUBSCRIPTION_INCONSISTENT_START_DATE = '91917';
325
+ const SUBSCRIPTION_INVALID_REQUEST_FORMAT = '91921';
326
+ const SUBSCRIPTION_MERCHANT_ACCOUNT_ID_IS_INVALID = '91901';
327
+ const SUBSCRIPTION_MISMATCH_CURRENCY_ISO_CODE = '91923';
328
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_CANNOT_BE_BLANK = '91912';
329
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_IS_TOO_SMALL = '91909';
330
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_MUST_BE_GREATER_THAN_ZERO = '91907';
331
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_MUST_BE_NUMERIC = '91906';
332
+ const SUBSCRIPTION_PAYMENT_METHOD_NONCE_CARD_TYPE_IS_NOT_ACCEPTED = '91924';
333
+ const SUBSCRIPTION_PAYMENT_METHOD_NONCE_IS_INVALID = '91925';
334
+ const SUBSCRIPTION_PAYMENT_METHOD_NONCE_NOT_ASSOCIATED_WITH_CUSTOMER = '91926';
335
+ const SUBSCRIPTION_PAYMENT_METHOD_NONCE_UNVAULTED_CARD_IS_NOT_ACCEPTED = '91927';
336
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_CARD_TYPE_IS_NOT_ACCEPTED = '91902';
337
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_IS_INVALID = '91903';
338
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_NOT_ASSOCIATED_WITH_CUSTOMER = '91905';
339
+ const SUBSCRIPTION_PLAN_BILLING_FREQUENCY_CANNOT_BE_UPDATED = '91922';
340
+ const SUBSCRIPTION_PLAN_ID_IS_INVALID = '91904';
341
+ const SUBSCRIPTION_PRICE_CANNOT_BE_BLANK = '81903';
342
+ const SUBSCRIPTION_PRICE_FORMAT_IS_INVALID = '81904';
343
+ const SUBSCRIPTION_PRICE_IS_TOO_LARGE = '81923';
344
+ const SUBSCRIPTION_STATUS_IS_CANCELED = '81905';
345
+ const SUBSCRIPTION_TOKEN_FORMAT_IS_INVALID = '81906';
346
+ const SUBSCRIPTION_TRIAL_DURATION_FORMAT_IS_INVALID = '81907';
347
+ const SUBSCRIPTION_TRIAL_DURATION_IS_REQUIRED = '81908';
348
+ const SUBSCRIPTION_TRIAL_DURATION_UNIT_IS_INVALID = '81909';
349
+
350
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_CANNOT_BE_BLANK = '92003';
351
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_IS_INVALID = '92002';
352
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_IS_TOO_LARGE = '92023';
353
+ const SUBSCRIPTION_MODIFICATION_CANNOT_EDIT_MODIFICATIONS_ON_PAST_DUE_SUBSCRIPTION = '92022';
354
+ const SUBSCRIPTION_MODIFICATION_CANNOT_UPDATE_AND_REMOVE = '92015';
355
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_INCORRECT_KIND = '92020';
356
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_INVALID = '92011';
357
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_REQUIRED = '92012';
358
+ const SUBSCRIPTION_MODIFICATION_ID_TO_REMOVE_IS_INCORRECT_KIND = '92021';
359
+ const SUBSCRIPTION_MODIFICATION_ID_TO_REMOVE_IS_INVALID = '92025';
360
+ const SUBSCRIPTION_MODIFICATION_ID_TO_REMOVE_IS_NOT_PRESENT = '92016';
361
+ const SUBSCRIPTION_MODIFICATION_INCONSISTENT_NUMBER_OF_BILLING_CYCLES = '92018';
362
+ const SUBSCRIPTION_MODIFICATION_INHERITED_FROM_ID_IS_INVALID = '92013';
363
+ const SUBSCRIPTION_MODIFICATION_INHERITED_FROM_ID_IS_REQUIRED = '92014';
364
+ const SUBSCRIPTION_MODIFICATION_MISSING = '92024';
365
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_CANNOT_BE_BLANK = '92017';
366
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_IS_INVALID = '92005';
367
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_MUST_BE_GREATER_THAN_ZERO = '92019';
368
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_CANNOT_BE_BLANK = '92004';
369
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_IS_INVALID = '92001';
370
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_MUST_BE_GREATER_THAN_ZERO = '92010';
371
+
372
+ const TRANSACTION_AMOUNT_CANNOT_BE_NEGATIVE = '81501';
373
+ const TRANSACTION_AMOUNT_FORMAT_IS_INVALID = '81503';
374
+ const TRANSACTION_AMOUNT_IS_INVALID = '81503';
375
+ const TRANSACTION_AMOUNT_IS_REQUIRED = '81502';
376
+ const TRANSACTION_AMOUNT_IS_TOO_LARGE = '81528';
377
+ const TRANSACTION_AMOUNT_MUST_BE_GREATER_THAN_ZERO = '81531';
378
+ const TRANSACTION_BILLING_ADDRESS_CONFLICT = '91530';
379
+ const TRANSACTION_CANNOT_BE_VOIDED = '91504';
380
+ const TRANSACTION_CANNOT_CLONE_CREDIT = '91543';
381
+ const TRANSACTION_CANNOT_CLONE_TRANSACTION_WITH_PAYPAL_ACCOUNT = '91573';
382
+ const TRANSACTION_CANNOT_CLONE_TRANSACTION_WITH_VAULT_CREDIT_CARD = '91540';
383
+ const TRANSACTION_CANNOT_CLONE_UNSUCCESSFUL_TRANSACTION = '91542';
384
+ const TRANSACTION_CANNOT_CLONE_VOICE_AUTHORIZATIONS = '91541';
385
+ const TRANSACTION_CANNOT_HOLD_IN_ESCROW = '91560';
386
+ const TRANSACTION_CANNOT_PARTIALLY_REFUND_ESCROWED_TRANSACTION = '91563';
387
+ const TRANSACTION_CANNOT_REFUND_CREDIT = '91505';
388
+ const TRANSACTION_CANNOT_REFUND_SETTLING_TRANSACTION = '91574';
389
+ const TRANSACTION_CANNOT_REFUND_UNLESS_SETTLED = '91506';
390
+ const TRANSACTION_CANNOT_REFUND_WITH_PENDING_MERCHANT_ACCOUNT = '91559';
391
+ const TRANSACTION_CANNOT_REFUND_WITH_SUSPENDED_MERCHANT_ACCOUNT = '91538';
392
+ const TRANSACTION_CANNOT_CANCEL_RELEASE = '91562';
393
+ const TRANSACTION_CANNOT_RELEASE_FROM_ESCROW = '91561';
394
+ const TRANSACTION_CANNOT_SUBMIT_FOR_SETTLEMENT = '91507';
395
+ const TRANSACTION_CANNOT_SIMULATE_SETTLEMENT = '91575';
396
+ const TRANSACTION_CHANNEL_IS_TOO_LONG = '91550';
397
+ const TRANSACTION_CREDIT_CARD_IS_REQUIRED = '91508';
398
+ const TRANSACTION_CUSTOMER_DEFAULT_PAYMENT_METHOD_CARD_TYPE_IS_NOT_ACCEPTED = '81509';
399
+ const TRANSACTION_CUSTOMER_DOES_NOT_HAVE_CREDIT_CARD = '91511';
400
+ const TRANSACTION_CUSTOMER_ID_IS_INVALID = '91510';
401
+ const TRANSACTION_CUSTOM_FIELD_IS_INVALID = '91526';
402
+ const TRANSACTION_CUSTOM_FIELD_IS_TOO_LONG = '81527';
403
+ const TRANSACTION_HAS_ALREADY_BEEN_REFUNDED = '91512';
404
+ const TRANSACTION_MERCHANT_ACCOUNT_DOES_NOT_SUPPORT_MOTO = '91558';
405
+ const TRANSACTION_MERCHANT_ACCOUNT_DOES_NOT_SUPPORT_REFUNDS = '91547';
406
+ const TRANSACTION_MERCHANT_ACCOUNT_ID_IS_INVALID = '91513';
407
+ const TRANSACTION_MERCHANT_ACCOUNT_IS_SUSPENDED = '91514';
408
+ const TRANSACTION_MERCHANT_ACCOUNT_NAME_IS_INVALID = '91513'; //Deprecated
409
+ const TRANSACTION_OPTIONS_SUBMIT_FOR_SETTLEMENT_IS_REQUIRED_FOR_CLONING = '91544';
410
+ const TRANSACTION_OPTIONS_USE_BILLING_FOR_SHIPPING_DISABLED = '91572';
411
+ const TRANSACTION_OPTIONS_VAULT_IS_DISABLED = '91525';
412
+ const TRANSACTION_OPTIONS_PAY_PAL_CUSTOM_FIELD_TOO_LONG = '91580';
413
+ const TRANSACTION_ORDER_ID_IS_TOO_LONG = '91501';
414
+ const TRANSACTION_PAYMENT_INSTRUMENT_NOT_SUPPORTED_BY_MERCHANT_ACCOUNT = '91577';
415
+ const TRANSACTION_PAYMENT_METHOD_CONFLICT = '91515';
416
+ const TRANSACTION_PAYMENT_METHOD_CONFLICT_WITH_VENMO_SDK = '91549';
417
+ const TRANSACTION_PAYMENT_METHOD_DOES_NOT_BELONG_TO_CUSTOMER = '91516';
418
+ const TRANSACTION_PAYMENT_METHOD_DOES_NOT_BELONG_TO_SUBSCRIPTION = '91527';
419
+ const TRANSACTION_PAYMENT_METHOD_NONCE_CONSUMED = '91564';
420
+ const TRANSACTION_PAYMENT_METHOD_NONCE_UNKNOWN = '91565';
421
+ const TRANSACTION_PAYMENT_METHOD_NONCE_LOCKED = '91566';
422
+ const TRANSACTION_PAYMENT_METHOD_NONCE_CARD_TYPE_IS_NOT_ACCEPTED = '91567';
423
+ const TRANSACTION_PAYMENT_METHOD_TOKEN_CARD_TYPE_IS_NOT_ACCEPTED = '91517';
424
+ const TRANSACTION_PAYMENT_METHOD_TOKEN_IS_INVALID = '91518';
425
+ const TRANSACTION_PAYPAL_NOT_ENABLED = '91576';
426
+ const TRANSACTION_PAY_PAL_AUTH_EXPIRED = '91579';
427
+ const TRANSACTION_PROCESSOR_AUTHORIZATION_CODE_CANNOT_BE_SET = '91519';
428
+ const TRANSACTION_PROCESSOR_AUTHORIZATION_CODE_IS_INVALID = '81520';
429
+ const TRANSACTION_PROCESSOR_DOES_NOT_SUPPORT_CREDITS = '91546';
430
+ const TRANSACTION_PROCESSOR_DOES_NOT_SUPPORT_VOICE_AUTHORIZATIONS = '91545';
431
+ const TRANSACTION_PURCHASE_ORDER_NUMBER_IS_INVALID = '91548';
432
+ const TRANSACTION_PURCHASE_ORDER_NUMBER_IS_TOO_LONG = '91537';
433
+ const TRANSACTION_REFUND_AMOUNT_IS_TOO_LARGE = '91521';
434
+ const TRANSACTION_SERVICE_FEE_AMOUNT_CANNOT_BE_NEGATIVE = '91554';
435
+ const TRANSACTION_SERVICE_FEE_AMOUNT_FORMAT_IS_INVALID = '91555';
436
+ const TRANSACTION_SERVICE_FEE_AMOUNT_IS_TOO_LARGE = '91556';
437
+ const TRANSACTION_SERVICE_FEE_AMOUNT_NOT_ALLOWED_ON_MASTER_MERCHANT_ACCOUNT = '91557';
438
+ const TRANSACTION_SERVICE_FEE_IS_NOT_ALLOWED_ON_CREDITS = '91552';
439
+ const TRANSACTION_SERVICE_FEE_NOT_ACCEPTED_FOR_PAYPAL = '91578';
440
+ const TRANSACTION_SETTLEMENT_AMOUNT_IS_LESS_THAN_SERVICE_FEE_AMOUNT = '91551';
441
+ const TRANSACTION_SETTLEMENT_AMOUNT_IS_TOO_LARGE = '91522';
442
+ const TRANSACTION_SHIPPING_ADDRESS_DOESNT_MATCH_CUSTOMER = '91581';
443
+ const TRANSACTION_SUBSCRIPTION_DOES_NOT_BELONG_TO_CUSTOMER = '91529';
444
+ const TRANSACTION_SUBSCRIPTION_ID_IS_INVALID = '91528';
445
+ const TRANSACTION_SUBSCRIPTION_STATUS_MUST_BE_PAST_DUE = '91531';
446
+ const TRANSACTION_SUB_MERCHANT_ACCOUNT_REQUIRES_SERVICE_FEE_AMOUNT = '91553';
447
+ const TRANSACTION_TAX_AMOUNT_CANNOT_BE_NEGATIVE = '81534';
448
+ const TRANSACTION_TAX_AMOUNT_FORMAT_IS_INVALID = '81535';
449
+ const TRANSACTION_TAX_AMOUNT_IS_TOO_LARGE = '81536';
450
+
451
+ const TRANSACTION_THREE_D_SECURE_AUTHENTICATION_FAILED = '81571';
452
+ const TRANSACTION_THREE_D_SECURE_TOKEN_IS_INVALID = '91568';
453
+ const TRANSACTION_THREE_D_SECURE_TRANSACTION_DATA_DOESNT_MATCH_VERIFY = '91570';
454
+ const TRANSACTION_TYPE_IS_INVALID = '91523';
455
+ const TRANSACTION_TYPE_IS_REQUIRED = '91524';
456
+ const TRANSACTION_UNSUPPORTED_VOICE_AUTHORIZATION = '91539';
457
+ }
lib/Braintree/Error/ErrorCollection.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Error handler
5
+ * Handles validation errors
6
+ *
7
+ * Contains a read-only property $error which is a ValidationErrorCollection
8
+ *
9
+ * @package Braintree
10
+ * @subpackage Errors
11
+ * @category Errors
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ *
14
+ * @property-read object $errors
15
+ */
16
+ class Braintree_Error_ErrorCollection
17
+ {
18
+ private $_errors;
19
+
20
+ public function __construct($errorData)
21
+ {
22
+ $this->_errors =
23
+ new Braintree_Error_ValidationErrorCollection($errorData);
24
+ }
25
+
26
+
27
+ /**
28
+ * Returns all of the validation errors at all levels of nesting in a single, flat array.
29
+ */
30
+ public function deepAll()
31
+ {
32
+ return $this->_errors->deepAll();
33
+ }
34
+
35
+ /**
36
+ * Returns the total number of validation errors at all levels of nesting. For example,
37
+ *if creating a customer with a credit card and a billing address, and each of the customer,
38
+ * credit card, and billing address has 1 error, this method will return 3.
39
+ *
40
+ * @return int size
41
+ */
42
+ public function deepSize()
43
+ {
44
+ $size = $this->_errors->deepSize();
45
+ return $size;
46
+ }
47
+
48
+ /**
49
+ * return errors for the passed key name
50
+ *
51
+ * @param string $key
52
+ * @return mixed
53
+ */
54
+ public function forKey($key)
55
+ {
56
+ return $this->_errors->forKey($key);
57
+ }
58
+
59
+ /**
60
+ * return errors for the passed html field.
61
+ * For example, $result->errors->onHtmlField("transaction[customer][last_name]")
62
+ *
63
+ * @param string $field
64
+ * @return array
65
+ */
66
+ public function onHtmlField($field)
67
+ {
68
+ $pieces = preg_split("/[\[\]]+/", $field, 0, PREG_SPLIT_NO_EMPTY);
69
+ $errors = $this;
70
+ foreach(array_slice($pieces, 0, -1) as $key) {
71
+ $errors = $errors->forKey(Braintree_Util::delimiterToCamelCase($key));
72
+ if (!isset($errors)) { return array(); }
73
+ }
74
+ $finalKey = Braintree_Util::delimiterToCamelCase(end($pieces));
75
+ return $errors->onAttribute($finalKey);
76
+ }
77
+
78
+ /**
79
+ * Returns the errors at the given nesting level (see forKey) in a single, flat array:
80
+ *
81
+ * <code>
82
+ * $result = Braintree_Customer::create(...);
83
+ * $customerErrors = $result->errors->forKey('customer')->shallowAll();
84
+ * </code>
85
+ */
86
+ public function shallowAll()
87
+ {
88
+ return $this->_errors->shallowAll();
89
+ }
90
+
91
+ /**
92
+ *
93
+ * @ignore
94
+ */
95
+ public function __get($name)
96
+ {
97
+ $varName = "_$name";
98
+ return isset($this->$varName) ? $this->$varName : null;
99
+ }
100
+
101
+ /**
102
+ *
103
+ * @ignore
104
+ */
105
+ public function __toString()
106
+ {
107
+ return sprintf('%s', $this->_errors);
108
+ }
109
+ }
lib/Braintree/Error/Validation.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * error object returned as part of a validation error collection
4
+ * provides read-only access to $attribute, $code, and $message
5
+ *
6
+ * <b>== More information ==</b>
7
+ *
8
+ * For more detailed information on Validation errors, see {@link http://www.braintreepayments.com/gateway/validation-errors http://www.braintreepaymentsolutions.com/gateway/validation-errors}
9
+ *
10
+ * @package Braintree
11
+ * @subpackage Error
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ *
14
+ * @property-read string $attribute
15
+ * @property-read string $code
16
+ * @property-read string $message
17
+ */
18
+ class Braintree_Error_Validation
19
+ {
20
+ private $_attribute;
21
+ private $_code;
22
+ private $_message;
23
+
24
+ /**
25
+ * @ignore
26
+ * @param array $attributes
27
+ */
28
+ public function __construct($attributes)
29
+ {
30
+ $this->_initializeFromArray($attributes);
31
+ }
32
+ /**
33
+ * initializes instance properties from the keys/values of an array
34
+ * @ignore
35
+ * @access protected
36
+ * @param array $attributes array of properties to set - single level
37
+ * @return none
38
+ */
39
+ private function _initializeFromArray($attributes)
40
+ {
41
+ foreach($attributes AS $name => $value) {
42
+ $varName = "_$name";
43
+ $this->$varName = Braintree_Util::delimiterToCamelCase($value, '_');
44
+ }
45
+ }
46
+
47
+ /**
48
+ *
49
+ * @ignore
50
+ */
51
+ public function __get($name)
52
+ {
53
+ $varName = "_$name";
54
+ return isset($this->$varName) ? $this->$varName : null;
55
+ }
56
+ }
lib/Braintree/Error/ValidationErrorCollection.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * collection of errors enumerating all validation errors for a given request
4
+ *
5
+ * <b>== More information ==</b>
6
+ *
7
+ * For more detailed information on Validation errors, see {@link http://www.braintreepayments.com/gateway/validation-errors http://www.braintreepaymentsolutions.com/gateway/validation-errors}
8
+ *
9
+ * @package Braintree
10
+ * @subpackage Error
11
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
12
+ *
13
+ * @property-read array $errors
14
+ * @property-read array $nested
15
+ */
16
+ class Braintree_Error_ValidationErrorCollection extends Braintree_Collection
17
+ {
18
+ private $_errors = array();
19
+ private $_nested = array();
20
+
21
+ /**
22
+ * @ignore
23
+ */
24
+ public function __construct($data)
25
+ {
26
+ foreach($data AS $key => $errorData)
27
+ // map errors to new collections recursively
28
+ if ($key == 'errors') {
29
+ foreach ($errorData AS $error) {
30
+ $this->_errors[] = new Braintree_Error_Validation($error);
31
+ }
32
+ } else {
33
+ $this->_nested[$key] = new Braintree_Error_ValidationErrorCollection($errorData);
34
+ }
35
+
36
+ }
37
+
38
+ public function deepAll()
39
+ {
40
+ $validationErrors = array_merge(array(), $this->_errors);
41
+ foreach($this->_nested as $nestedErrors)
42
+ {
43
+ $validationErrors = array_merge($validationErrors, $nestedErrors->deepAll());
44
+ }
45
+ return $validationErrors;
46
+ }
47
+
48
+ public function deepSize()
49
+ {
50
+ $total = sizeof($this->_errors);
51
+ foreach($this->_nested as $_nestedErrors)
52
+ {
53
+ $total = $total + $_nestedErrors->deepSize();
54
+ }
55
+ return $total;
56
+ }
57
+
58
+ public function forIndex($index)
59
+ {
60
+ return $this->forKey("index" . $index);
61
+ }
62
+
63
+ public function forKey($key)
64
+ {
65
+ return isset($this->_nested[$key]) ? $this->_nested[$key] : null;
66
+ }
67
+
68
+ public function onAttribute($attribute)
69
+ {
70
+ $matches = array();
71
+ foreach ($this->_errors AS $key => $error) {
72
+ if($error->attribute == $attribute) {
73
+ $matches[] = $error;
74
+ }
75
+ }
76
+ return $matches;
77
+ }
78
+
79
+
80
+ public function shallowAll()
81
+ {
82
+ return $this->_errors;
83
+ }
84
+
85
+ /**
86
+ *
87
+ * @ignore
88
+ */
89
+ public function __get($name)
90
+ {
91
+ $varName = "_$name";
92
+ return isset($this->$varName) ? $this->$varName : null;
93
+ }
94
+
95
+ /**
96
+ * @ignore
97
+ */
98
+ public function __toString()
99
+ {
100
+ $output = array();
101
+
102
+ // TODO: implement scope
103
+ if (!empty($this->_errors)) {
104
+ $output[] = $this->_inspect($this->_errors);
105
+ }
106
+ if (!empty($this->_nested)) {
107
+ foreach ($this->_nested AS $key => $values) {
108
+ $output[] = $this->_inspect($this->_nested);
109
+ }
110
+ }
111
+ return join(', ', $output);
112
+ }
113
+
114
+ /**
115
+ * @ignore
116
+ */
117
+ private function _inspect($errors, $scope = null)
118
+ {
119
+ $eOutput = '[' . __CLASS__ . '/errors:[';
120
+ foreach($errors AS $error => $errorObj) {
121
+ $outputErrs[] = "({$errorObj->error['code']} {$errorObj->error['message']})";
122
+ }
123
+ $eOutput .= join(', ', $outputErrs) . ']]';
124
+
125
+ return $eOutput;
126
+ }
127
+ }
lib/Braintree/Exception.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * super class for all Braintree exceptions
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception extends Exception
10
+ {
11
+ }
lib/Braintree/Exception/Authentication.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when authentication fails.
4
+ * This may be caused by an incorrect Braintree_Configuration
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Exception
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ */
10
+ class Braintree_Exception_Authentication extends Braintree_Exception
11
+ {
12
+
13
+ }
lib/Braintree/Exception/Authorization.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when authorization fails
4
+ * Raised when the API key being used is not authorized to perform
5
+ * the attempted action according to the roles assigned to the user
6
+ * who owns the API key.
7
+ *
8
+ * @package Braintree
9
+ * @subpackage Exception
10
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
11
+ */
12
+ class Braintree_Exception_Authorization extends Braintree_Exception
13
+ {
14
+
15
+ }
lib/Braintree/Exception/Configuration.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the Braintree library is not completely configured.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @see Braintree_Configuration
8
+ */
9
+ class Braintree_Exception_Configuration extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/DownForMaintenance.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the gateway is down for maintenance.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_DownForMaintenance extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/ForgedQueryString.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a suspected forged query string is present
4
+ * Raised from methods that confirm transparent redirect requests
5
+ * when the given query string cannot be verified. This may indicate
6
+ * an attempted hack on the merchant's transparent redirect
7
+ * confirmation URL.
8
+ *
9
+ * @package Braintree
10
+ * @subpackage Exception
11
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
12
+ */
13
+ class Braintree_Exception_ForgedQueryString extends Braintree_Exception
14
+ {
15
+
16
+ }
lib/Braintree/Exception/InvalidSignature.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Exception_InvalidSignature extends Braintree_Exception
3
+ {
4
+
5
+ }
lib/Braintree/Exception/NotFound.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a record could not be found.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_NotFound extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/SSLCaFileNotFound.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the SSL CaFile is not found.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_SSLCaFileNotFound extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/SSLCertificate.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the SSL certificate fails verification.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_SSLCertificate extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/ServerError.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when an unexpected server error occurs.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_ServerError extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/Unexpected.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when an error occurs that the client library is not built to handle.
4
+ * This shouldn't happen.
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Exception
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ */
10
+ class Braintree_Exception_Unexpected extends Braintree_Exception
11
+ {
12
+
13
+ }
lib/Braintree/Exception/UpgradeRequired.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a client library must be upgraded.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_UpgradeRequired extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Exception/ValidationsFailed.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised from non-validating methods when gateway validations fail.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Exception_ValidationsFailed extends Braintree_Exception
10
+ {
11
+
12
+ }
lib/Braintree/Gateway.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Gateway module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Gateway
10
+ {
11
+ public $config;
12
+
13
+ public function __construct($config)
14
+ {
15
+ if (is_array($config)) {
16
+ $config = new Braintree_Configuration($config);
17
+ }
18
+ $config->assertValid();
19
+ $this->config = $config;
20
+ }
21
+
22
+ public function customer()
23
+ {
24
+ return new Braintree_CustomerGateway($this);
25
+ }
26
+
27
+ public function addOn()
28
+ {
29
+ return new Braintree_AddOnGateway($this);
30
+ }
31
+
32
+ public function address()
33
+ {
34
+ return new Braintree_AddressGateway($this);
35
+ }
36
+
37
+ public function clientToken()
38
+ {
39
+ return new Braintree_ClientTokenGateway($this);
40
+ }
41
+
42
+ public function creditCard()
43
+ {
44
+ return new Braintree_CreditCardGateway($this);
45
+ }
46
+
47
+ public function creditCardVerification()
48
+ {
49
+ return new Braintree_CreditCardVerificationGateway($this);
50
+ }
51
+
52
+ public function discount()
53
+ {
54
+ return new Braintree_DiscountGateway($this);
55
+ }
56
+
57
+ public function merchantAccount()
58
+ {
59
+ return new Braintree_MerchantAccountGateway($this);
60
+ }
61
+
62
+ public function paymentMethod()
63
+ {
64
+ return new Braintree_PaymentMethodGateway($this);
65
+ }
66
+
67
+ public function paymentMethodNonce()
68
+ {
69
+ return new Braintree_PaymentMethodNonceGateway($this);
70
+ }
71
+
72
+ public function payPalAccount()
73
+ {
74
+ return new Braintree_PayPalAccountGateway($this);
75
+ }
76
+
77
+ public function plan()
78
+ {
79
+ return new Braintree_PlanGateway($this);
80
+ }
81
+
82
+ public function settlementBatchSummary()
83
+ {
84
+ return new Braintree_SettlementBatchSummaryGateway($this);
85
+ }
86
+
87
+ public function subscription()
88
+ {
89
+ return new Braintree_SubscriptionGateway($this);
90
+ }
91
+
92
+ public function transaction()
93
+ {
94
+ return new Braintree_TransactionGateway($this);
95
+ }
96
+
97
+ public function transparentRedirect()
98
+ {
99
+ return new Braintree_TransparentRedirectGateway($this);
100
+ }
101
+ }
lib/Braintree/Http.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree HTTP Client
4
+ * processes Http requests using curl
5
+ *
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ */
8
+ class Braintree_Http
9
+ {
10
+ protected $_config;
11
+
12
+ public function __construct($config)
13
+ {
14
+ $this->_config = $config;
15
+ }
16
+
17
+ public function delete($path)
18
+ {
19
+ $response = $this->_doRequest('DELETE', $path);
20
+ if($response['status'] === 200) {
21
+ return true;
22
+ } else {
23
+ Braintree_Util::throwStatusCodeException($response['status']);
24
+ }
25
+ }
26
+
27
+ public function get($path)
28
+ {
29
+ $response = $this->_doRequest('GET', $path);
30
+ if($response['status'] === 200) {
31
+ return Braintree_Xml::buildArrayFromXml($response['body']);
32
+ } else {
33
+ Braintree_Util::throwStatusCodeException($response['status']);
34
+ }
35
+ }
36
+
37
+ public function post($path, $params = null)
38
+ {
39
+ $response = $this->_doRequest('POST', $path, $this->_buildXml($params));
40
+ $responseCode = $response['status'];
41
+ if($responseCode === 200 || $responseCode === 201 || $responseCode === 422) {
42
+ return Braintree_Xml::buildArrayFromXml($response['body']);
43
+ } else {
44
+ Braintree_Util::throwStatusCodeException($responseCode);
45
+ }
46
+ }
47
+
48
+ public function put($path, $params = null)
49
+ {
50
+ $response = $this->_doRequest('PUT', $path, $this->_buildXml($params));
51
+ $responseCode = $response['status'];
52
+ if($responseCode === 200 || $responseCode === 201 || $responseCode === 422) {
53
+ return Braintree_Xml::buildArrayFromXml($response['body']);
54
+ } else {
55
+ Braintree_Util::throwStatusCodeException($responseCode);
56
+ }
57
+ }
58
+
59
+ private function _buildXml($params)
60
+ {
61
+ return empty($params) ? null : Braintree_Xml::buildXmlFromArray($params);
62
+ }
63
+
64
+ private function _doRequest($httpVerb, $path, $requestBody = null)
65
+ {
66
+ return $this->_doUrlRequest($httpVerb, $this->_config->baseUrl() . $path, $requestBody);
67
+ }
68
+
69
+ public function _doUrlRequest($httpVerb, $url, $requestBody = null)
70
+ {
71
+ $curl = curl_init();
72
+ curl_setopt($curl, CURLOPT_TIMEOUT, 60);
73
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpVerb);
74
+ curl_setopt($curl, CURLOPT_URL, $url);
75
+ curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
76
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array(
77
+ 'Accept: application/xml',
78
+ 'Content-Type: application/xml',
79
+ 'User-Agent: Braintree PHP Library ' . Braintree_Version::get(),
80
+ 'X-ApiVersion: ' . Braintree_Configuration::API_VERSION
81
+ ));
82
+ curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
83
+ curl_setopt($curl, CURLOPT_USERPWD, $this->_config->getPublicKey() . ':' . $this->_config->getPrivateKey());
84
+ // curl_setopt($curl, CURLOPT_VERBOSE, true);
85
+ if ($this->_config->sslOn()) {
86
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
87
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
88
+ curl_setopt($curl, CURLOPT_CAINFO, $this->_config->caFile());
89
+ }
90
+
91
+ if(!empty($requestBody)) {
92
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
93
+ }
94
+
95
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
96
+ $response = curl_exec($curl);
97
+ $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
98
+ curl_close($curl);
99
+ if ($this->_config->sslOn()) {
100
+ if ($httpStatus == 0) {
101
+ throw new Braintree_Exception_SSLCertificate();
102
+ }
103
+ }
104
+ return array('status' => $httpStatus, 'body' => $response);
105
+ }
106
+ }
lib/Braintree/Instance.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Class Instance template
4
+ * @package Braintree
5
+ * @subpackage Utility
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ * @abstract
8
+ */
9
+ abstract class Braintree_Instance
10
+ {
11
+ /**
12
+ *
13
+ * @param array $aAttribs
14
+ */
15
+ public function __construct($attributes)
16
+ {
17
+ if (!empty($attributes)) {
18
+ $this->_initializeFromArray($attributes);
19
+ }
20
+ }
21
+
22
+
23
+ /**
24
+ * returns private/nonexistent instance properties
25
+ * @access public
26
+ * @param var $name property name
27
+ * @return mixed contents of instance properties
28
+ */
29
+ public function __get($name)
30
+ {
31
+ if (array_key_exists($name, $this->_attributes)) {
32
+ return $this->_attributes[$name];
33
+ } else {
34
+ trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE);
35
+ return null;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * used by isset() and empty()
41
+ * @access public
42
+ * @param string $name property name
43
+ * @return boolean
44
+ */
45
+ public function __isset($name)
46
+ {
47
+ return array_key_exists($name, $this->_attributes);
48
+ }
49
+
50
+ /**
51
+ * create a printable representation of the object as:
52
+ * ClassName[property=value, property=value]
53
+ * @return var
54
+ */
55
+ public function __toString()
56
+ {
57
+ $objOutput = Braintree_Util::implodeAssociativeArray($this->_attributes);
58
+ return get_class($this) .'['.$objOutput.']';
59
+ }
60
+ /**
61
+ * initializes instance properties from the keys/values of an array
62
+ * @ignore
63
+ * @access protected
64
+ * @param <type> $aAttribs array of properties to set - single level
65
+ * @return none
66
+ */
67
+ private function _initializeFromArray($attributes)
68
+ {
69
+ $this->_attributes = $attributes;
70
+ }
71
+
72
+ }
lib/Braintree/IsNode.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_IsNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerms = array();
9
+ }
10
+
11
+ function is($value)
12
+ {
13
+ $this->searchTerms['is'] = strval($value);
14
+ return $this;
15
+ }
16
+
17
+ function toParam()
18
+ {
19
+ return $this->searchTerms;
20
+ }
21
+ }
lib/Braintree/KeyValueNode.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_KeyValueNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerm = True;
9
+
10
+ }
11
+
12
+ function is($value)
13
+ {
14
+ $this->searchTerm = $value;
15
+ return $this;
16
+ }
17
+
18
+ function toParam()
19
+ {
20
+ return $this->searchTerm;
21
+ }
22
+ }
lib/Braintree/MerchantAccount.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccount extends Braintree
4
+ {
5
+ const STATUS_ACTIVE = 'active';
6
+ const STATUS_PENDING = 'pending';
7
+ const STATUS_SUSPENDED = 'suspended';
8
+
9
+ const FUNDING_DESTINATION_BANK = 'bank';
10
+ const FUNDING_DESTINATION_EMAIL = 'email';
11
+ const FUNDING_DESTINATION_MOBILE_PHONE = 'mobile_phone';
12
+
13
+ public static function factory($attributes)
14
+ {
15
+ $instance = new self();
16
+ $instance->_initialize($attributes);
17
+ return $instance;
18
+ }
19
+
20
+ protected function _initialize($merchantAccountAttribs)
21
+ {
22
+ $this->_attributes = $merchantAccountAttribs;
23
+
24
+ if (isset($merchantAccountAttribs['individual'])) {
25
+ $individual = $merchantAccountAttribs['individual'];
26
+ $this->_set('individualDetails', Braintree_MerchantAccount_IndividualDetails::Factory($individual));
27
+ }
28
+
29
+ if (isset($merchantAccountAttribs['business'])) {
30
+ $business = $merchantAccountAttribs['business'];
31
+ $this->_set('businessDetails', Braintree_MerchantAccount_BusinessDetails::Factory($business));
32
+ }
33
+
34
+ if (isset($merchantAccountAttribs['funding'])) {
35
+ $funding = $merchantAccountAttribs['funding'];
36
+ $this->_set('fundingDetails', new Braintree_MerchantAccount_FundingDetails($funding));
37
+ }
38
+
39
+ if (isset($merchantAccountAttribs['masterMerchantAccount'])) {
40
+ $masterMerchantAccount = $merchantAccountAttribs['masterMerchantAccount'];
41
+ $this->_set('masterMerchantAccount', Braintree_MerchantAccount::Factory($masterMerchantAccount));
42
+ }
43
+ }
44
+
45
+
46
+ // static methods redirecting to gateway
47
+
48
+ public static function create($attribs)
49
+ {
50
+ return Braintree_Configuration::gateway()->merchantAccount()->create($attribs);
51
+ }
52
+
53
+ public static function find($merchant_account_id)
54
+ {
55
+ return Braintree_Configuration::gateway()->merchantAccount()->find($merchant_account_id);
56
+ }
57
+
58
+ public static function update($merchant_account_id, $attributes)
59
+ {
60
+ return Braintree_Configuration::gateway()->merchantAccount()->update($merchant_account_id, $attributes);
61
+ }
62
+ }
lib/Braintree/MerchantAccount/AddressDetails.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccount_AddressDetails extends Braintree_Instance {
4
+ protected $_attributes = array();
5
+ }
lib/Braintree/MerchantAccount/BusinessDetails.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccount_BusinessDetails extends Braintree
4
+ {
5
+ protected function _initialize($businessAttribs)
6
+ {
7
+ $this->_attributes = $businessAttribs;
8
+ if (isset($businessAttribs['address'])) {
9
+ $this->_set('addressDetails', new Braintree_MerchantAccount_AddressDetails($businessAttribs['address']));
10
+ }
11
+ }
12
+
13
+ public static function factory($attributes)
14
+ {
15
+ $instance = new self();
16
+ $instance->_initialize($attributes);
17
+ return $instance;
18
+ }
19
+ }
lib/Braintree/MerchantAccount/FundingDetails.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccount_FundingDetails extends Braintree_Instance
4
+ {
5
+ protected $_attributes = array();
6
+ }
lib/Braintree/MerchantAccount/IndividualDetails.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccount_IndividualDetails extends Braintree
4
+ {
5
+ protected function _initialize($individualAttribs)
6
+ {
7
+ $this->_attributes = $individualAttribs;
8
+ if (isset($individualAttribs['address'])) {
9
+ $this->_set('addressDetails', new Braintree_MerchantAccount_AddressDetails($individualAttribs['address']));
10
+ }
11
+ }
12
+
13
+ public static function factory($attributes)
14
+ {
15
+ $instance = new self();
16
+ $instance->_initialize($attributes);
17
+ return $instance;
18
+ }
19
+ }
lib/Braintree/MerchantAccountGateway.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_MerchantAccountGateway
4
+ {
5
+ private $_gateway;
6
+ private $_config;
7
+ private $_http;
8
+
9
+ public function __construct($gateway)
10
+ {
11
+ $this->_gateway = $gateway;
12
+ $this->_config = $gateway->config;
13
+ $this->_http = new Braintree_Http($gateway->config);
14
+ }
15
+
16
+ public function create($attribs)
17
+ {
18
+ Braintree_Util::verifyKeys(self::detectSignature($attribs), $attribs);
19
+ return $this->_doCreate('/merchant_accounts/create_via_api', array('merchant_account' => $attribs));
20
+ }
21
+
22
+ public function find($merchant_account_id)
23
+ {
24
+ try {
25
+ $path = $this->_config->merchantPath() . '/merchant_accounts/' . $merchant_account_id;
26
+ $response = $this->_http->get($path);
27
+ return Braintree_MerchantAccount::factory($response['merchantAccount']);
28
+ } catch (Braintree_Exception_NotFound $e) {
29
+ throw new Braintree_Exception_NotFound('merchant account with id ' . $merchant_account_id . ' not found');
30
+ }
31
+ }
32
+
33
+ public function update($merchant_account_id, $attributes)
34
+ {
35
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
36
+ return $this->_doUpdate('/merchant_accounts/' . $merchant_account_id . '/update_via_api', array('merchant_account' => $attributes));
37
+ }
38
+
39
+ public static function detectSignature($attribs)
40
+ {
41
+ if (isset($attribs['applicantDetails'])) {
42
+ trigger_error("DEPRECATED: Passing applicantDetails to create is deprecated. Please use individual, business, and funding", E_USER_NOTICE);
43
+ return self::createDeprecatedSignature();
44
+ } else {
45
+ return self::createSignature();
46
+ }
47
+ }
48
+
49
+ public static function updateSignature()
50
+ {
51
+ $signature = self::createSignature();
52
+ unset($signature['tosAccepted']);
53
+ return $signature;
54
+ }
55
+
56
+ public static function createSignature()
57
+ {
58
+ $addressSignature = array('streetAddress', 'postalCode', 'locality', 'region');
59
+ $individualSignature = array(
60
+ 'firstName',
61
+ 'lastName',
62
+ 'email',
63
+ 'phone',
64
+ 'dateOfBirth',
65
+ 'ssn',
66
+ array('address' => $addressSignature)
67
+ );
68
+
69
+ $businessSignature = array(
70
+ 'dbaName',
71
+ 'legalName',
72
+ 'taxId',
73
+ array('address' => $addressSignature)
74
+ );
75
+
76
+ $fundingSignature = array(
77
+ 'routingNumber',
78
+ 'accountNumber',
79
+ 'destination',
80
+ 'email',
81
+ 'mobilePhone',
82
+ 'descriptor',
83
+ );
84
+
85
+ return array(
86
+ 'id',
87
+ 'tosAccepted',
88
+ 'masterMerchantAccountId',
89
+ array('individual' => $individualSignature),
90
+ array('funding' => $fundingSignature),
91
+ array('business' => $businessSignature)
92
+ );
93
+ }
94
+
95
+ public static function createDeprecatedSignature()
96
+ {
97
+ $applicantDetailsAddressSignature = array('streetAddress', 'postalCode', 'locality', 'region');
98
+ $applicantDetailsSignature = array(
99
+ 'companyName',
100
+ 'firstName',
101
+ 'lastName',
102
+ 'email',
103
+ 'phone',
104
+ 'dateOfBirth',
105
+ 'ssn',
106
+ 'taxId',
107
+ 'routingNumber',
108
+ 'accountNumber',
109
+ array('address' => $applicantDetailsAddressSignature)
110
+ );
111
+
112
+ return array(
113
+ array('applicantDetails' => $applicantDetailsSignature),
114
+ 'id',
115
+ 'tosAccepted',
116
+ 'masterMerchantAccountId'
117
+ );
118
+ }
119
+
120
+ public function _doCreate($subPath, $params)
121
+ {
122
+ $fullPath = $this->_config->merchantPath() . $subPath;
123
+ $response = $this->_http->post($fullPath, $params);
124
+
125
+ return $this->_verifyGatewayResponse($response);
126
+ }
127
+
128
+ private function _doUpdate($subPath, $params)
129
+ {
130
+ $fullPath = $this->_config->merchantPath() . $subPath;
131
+ $response = $this->_http->put($fullPath, $params);
132
+
133
+ return $this->_verifyGatewayResponse($response);
134
+ }
135
+
136
+ private function _verifyGatewayResponse($response)
137
+ {
138
+ if (isset($response['merchantAccount'])) {
139
+ // return a populated instance of Braintree_merchantAccount
140
+ return new Braintree_Result_Successful(
141
+ Braintree_MerchantAccount::factory($response['merchantAccount'])
142
+ );
143
+ } else if (isset($response['apiErrorResponse'])) {
144
+ return new Braintree_Result_Error($response['apiErrorResponse']);
145
+ } else {
146
+ throw new Braintree_Exception_Unexpected(
147
+ "Expected merchant account or apiErrorResponse"
148
+ );
149
+ }
150
+ }
151
+ }
lib/Braintree/Modification.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Modification extends Braintree
3
+ {
4
+ protected function _initialize($attributes)
5
+ {
6
+ $this->_attributes = $attributes;
7
+
8
+ $addOnArray = array();
9
+ if (isset($attributes['addOns'])) {
10
+ foreach ($attributes['addOns'] AS $addOn) {
11
+ $addOnArray[] = Braintree_addOn::factory($addOn);
12
+ }
13
+ }
14
+ $this->_attributes['addOns'] = $addOnArray;
15
+ }
16
+
17
+ public static function factory($attributes)
18
+ {
19
+ $instance = new self();
20
+ $instance->_initialize($attributes);
21
+ return $instance;
22
+ }
23
+ }
lib/Braintree/MultipleValueNode.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_MultipleValueNode
4
+ {
5
+ function __construct($name, $allowedValues = array())
6
+ {
7
+ $this->name = $name;
8
+ $this->items = array();
9
+ $this->allowedValues = $allowedValues;
10
+ }
11
+
12
+ function in($values)
13
+ {
14
+ $bad_values = array_diff($values, $this->allowedValues);
15
+ if (count($this->allowedValues) > 0 && count($bad_values) > 0) {
16
+ $message = 'Invalid argument(s) for ' . $this->name . ':';
17
+ foreach ($bad_values AS $bad_value) {
18
+ $message .= ' ' . $bad_value;
19
+ }
20
+
21
+ throw new InvalidArgumentException($message);
22
+ }
23
+
24
+ $this->items = $values;
25
+ return $this;
26
+ }
27
+
28
+ function is($value)
29
+ {
30
+ return $this->in(array($value));
31
+ }
32
+
33
+ function toParam()
34
+ {
35
+ return $this->items;
36
+ }
37
+ }
lib/Braintree/MultipleValueOrTextNode.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_MultipleValueOrTextNode extends Braintree_MultipleValueNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ parent::__construct($name);
8
+ $this->textNode = new Braintree_TextNode($name);
9
+ }
10
+
11
+ function contains($value)
12
+ {
13
+ $this->textNode->contains($value);
14
+ return $this;
15
+ }
16
+
17
+ function endsWith($value)
18
+ {
19
+ $this->textNode->endsWith($value);
20
+ return $this;
21
+ }
22
+
23
+ function is($value)
24
+ {
25
+ $this->textNode->is($value);
26
+ return $this;
27
+ }
28
+
29
+ function isNot($value)
30
+ {
31
+ $this->textNode->isNot($value);
32
+ return $this;
33
+ }
34
+
35
+ function startsWith($value)
36
+ {
37
+ $this->textNode->startsWith($value);
38
+ return $this;
39
+ }
40
+
41
+ function toParam()
42
+ {
43
+ return array_merge(parent::toParam(), $this->textNode->toParam());
44
+ }
45
+ }
lib/Braintree/PartialMatchNode.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_PartialMatchNode extends Braintree_EqualityNode
4
+ {
5
+ function startsWith($value)
6
+ {
7
+ $this->searchTerms["starts_with"] = strval($value);
8
+ return $this;
9
+ }
10
+
11
+ function endsWith($value)
12
+ {
13
+ $this->searchTerms["ends_with"] = strval($value);
14
+ return $this;
15
+ }
16
+ }
lib/Braintree/PartnerMerchant.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Partner Merchant information that is generated when a partner is connected
4
+ * to or disconnected from a user.
5
+ *
6
+ * Creates an instance of PartnerMerchants
7
+ *
8
+ * @package Braintree
9
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
10
+ *
11
+ * @property-read string $merchantPublicId
12
+ * @property-read string $publicKey
13
+ * @property-read string $privateKey
14
+ * @property-read string $clientSideEncryptionKey
15
+ * @property-read string $partnerMerchantId
16
+ * @uses Braintree_Instance inherits methods
17
+ */
18
+ class Braintree_PartnerMerchant extends Braintree
19
+ {
20
+ protected $_attributes = array();
21
+
22
+ /**
23
+ * @ignore
24
+ */
25
+ public static function factory($attributes)
26
+ {
27
+ $instance = new self();
28
+ $instance->_initialize($attributes);
29
+
30
+ return $instance;
31
+ }
32
+
33
+ /**
34
+ * @ignore
35
+ */
36
+ protected function _initialize($attributes)
37
+ {
38
+ $this->_attributes = $attributes;
39
+ }
40
+ }
lib/Braintree/PayPalAccount.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PayPalAccount module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Manages Braintree PayPalAccounts
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ * @property-read string $email
21
+ * @property-read string $token
22
+ * @property-read string $imageUrl
23
+ */
24
+ class Braintree_PayPalAccount extends Braintree
25
+ {
26
+ /**
27
+ * factory method: returns an instance of Braintree_PayPalAccount
28
+ * to the requesting method, with populated properties
29
+ *
30
+ * @ignore
31
+ * @return object instance of Braintree_PayPalAccount
32
+ */
33
+ public static function factory($attributes)
34
+ {
35
+ $instance = new self();
36
+ $instance->_initialize($attributes);
37
+ return $instance;
38
+ }
39
+
40
+ /* instance methods */
41
+
42
+ /**
43
+ * returns false if default is null or false
44
+ *
45
+ * @return boolean
46
+ */
47
+ public function isDefault()
48
+ {
49
+ return $this->default;
50
+ }
51
+
52
+ /**
53
+ * sets instance properties from an array of values
54
+ *
55
+ * @access protected
56
+ * @param array $paypalAccountAttribs array of paypalAccount data
57
+ * @return none
58
+ */
59
+ protected function _initialize($paypalAccountAttribs)
60
+ {
61
+ // set the attributes
62
+ $this->_attributes = $paypalAccountAttribs;
63
+
64
+ $subscriptionArray = array();
65
+ if (isset($paypalAccountAttribs['subscriptions'])) {
66
+ foreach ($paypalAccountAttribs['subscriptions'] AS $subscription) {
67
+ $subscriptionArray[] = Braintree_Subscription::factory($subscription);
68
+ }
69
+ }
70
+
71
+ $this->_set('subscriptions', $subscriptionArray);
72
+ }
73
+
74
+ /**
75
+ * create a printable representation of the object as:
76
+ * ClassName[property=value, property=value]
77
+ * @return string
78
+ */
79
+ public function __toString()
80
+ {
81
+ return __CLASS__ . '[' .
82
+ Braintree_Util::attributesToString($this->_attributes) .']';
83
+ }
84
+
85
+
86
+ // static methods redirecting to gateway
87
+
88
+ public static function find($token)
89
+ {
90
+ return Braintree_Configuration::gateway()->payPalAccount()->find($token);
91
+ }
92
+
93
+ public static function update($token, $attributes)
94
+ {
95
+ return Braintree_Configuration::gateway()->payPalAccount()->update($token, $attributes);
96
+ }
97
+
98
+ public static function delete($token)
99
+ {
100
+ return Braintree_Configuration::gateway()->payPalAccount()->delete($token);
101
+ }
102
+
103
+ public static function sale($token, $transactionAttribs)
104
+ {
105
+ return Braintree_Configuration::gateway()->payPalAccount()->sale($token, $transactionAttribs);
106
+ }
107
+ }
lib/Braintree/PayPalAccountGateway.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PayPalAccountGateway module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Manages Braintree PayPalAccounts
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ */
20
+ class Braintree_PayPalAccountGateway
21
+ {
22
+ private $_gateway;
23
+ private $_config;
24
+ private $_http;
25
+
26
+ public function __construct($gateway)
27
+ {
28
+ $this->_gateway = $gateway;
29
+ $this->_config = $gateway->config;
30
+ $this->_http = new Braintree_Http($gateway->config);
31
+ }
32
+
33
+
34
+ /**
35
+ * find a paypalAccount by token
36
+ *
37
+ * @access public
38
+ * @param string $token paypal accountunique id
39
+ * @return object Braintree_PayPalAccount
40
+ * @throws Braintree_Exception_NotFound
41
+ */
42
+ public function find($token)
43
+ {
44
+ $this->_validateId($token);
45
+ try {
46
+ $path = $this->_config->merchantPath() . '/payment_methods/paypal_account/' . $token;
47
+ $response = $this->_http->get($path);
48
+ return Braintree_PayPalAccount::factory($response['paypalAccount']);
49
+ } catch (Braintree_Exception_NotFound $e) {
50
+ throw new Braintree_Exception_NotFound(
51
+ 'paypal account with token ' . $token . ' not found'
52
+ );
53
+ }
54
+
55
+ }
56
+
57
+ /**
58
+ * updates the paypalAccount record
59
+ *
60
+ * if calling this method in context, $token
61
+ * is the 2nd attribute. $token is not sent in object context.
62
+ *
63
+ * @access public
64
+ * @param array $attributes
65
+ * @param string $token (optional)
66
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
67
+ */
68
+ public function update($token, $attributes)
69
+ {
70
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
71
+ $this->_validateId($token);
72
+ return $this->_doUpdate('put', '/payment_methods/paypal_account/' . $token, array('paypalAccount' => $attributes));
73
+ }
74
+
75
+ public function delete($token)
76
+ {
77
+ $this->_validateId($token);
78
+ $path = $this->_config->merchantPath() . '/payment_methods/paypal_account/' . $token;
79
+ $this->_http->delete($path);
80
+ return new Braintree_Result_Successful();
81
+ }
82
+
83
+ /**
84
+ * create a new sale for the current PayPal account
85
+ *
86
+ * @param string $token
87
+ * @param array $transactionAttribs
88
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
89
+ * @see Braintree_Transaction::sale()
90
+ */
91
+ public function sale($token, $transactionAttribs)
92
+ {
93
+ $this->_validateId($token);
94
+ return Braintree_Transaction::sale(
95
+ array_merge(
96
+ $transactionAttribs,
97
+ array('paymentMethodToken' => $token)
98
+ )
99
+ );
100
+ }
101
+
102
+ public static function updateSignature()
103
+ {
104
+ return array(
105
+ 'token',
106
+ array('options' => array('makeDefault'))
107
+ );
108
+ }
109
+
110
+ /**
111
+ * sends the update request to the gateway
112
+ *
113
+ * @ignore
114
+ * @param string $subPath
115
+ * @param array $params
116
+ * @return mixed
117
+ */
118
+ private function _doUpdate($httpVerb, $subPath, $params)
119
+ {
120
+ $fullPath = $this->_config->merchantPath() . $subPath;
121
+ $response = $this->_http->$httpVerb($fullPath, $params);
122
+ return $this->_verifyGatewayResponse($response);
123
+ }
124
+
125
+ /**
126
+ * generic method for validating incoming gateway responses
127
+ *
128
+ * creates a new Braintree_PayPalAccount object and encapsulates
129
+ * it inside a Braintree_Result_Successful object, or
130
+ * encapsulates a Braintree_Errors object inside a Result_Error
131
+ * alternatively, throws an Unexpected exception if the response is invalid.
132
+ *
133
+ * @ignore
134
+ * @param array $response gateway response values
135
+ * @return object Result_Successful or Result_Error
136
+ * @throws Braintree_Exception_Unexpected
137
+ */
138
+ private function _verifyGatewayResponse($response)
139
+ {
140
+ if (isset($response['paypalAccount'])) {
141
+ // return a populated instance of Braintree_PayPalAccount
142
+ return new Braintree_Result_Successful(
143
+ Braintree_PayPalAccount::factory($response['paypalAccount'])
144
+ );
145
+ } else if (isset($response['apiErrorResponse'])) {
146
+ return new Braintree_Result_Error($response['apiErrorResponse']);
147
+ } else {
148
+ throw new Braintree_Exception_Unexpected(
149
+ 'Expected paypal account or apiErrorResponse'
150
+ );
151
+ }
152
+ }
153
+
154
+ /**
155
+ * verifies that a valid paypal account identifier is being used
156
+ * @ignore
157
+ * @param string $identifier
158
+ * @param Optional $string $identifierType type of identifier supplied, default 'token'
159
+ * @throws InvalidArgumentException
160
+ */
161
+ private function _validateId($identifier = null, $identifierType = 'token')
162
+ {
163
+ if (empty($identifier)) {
164
+ throw new InvalidArgumentException(
165
+ 'expected paypal account id to be set'
166
+ );
167
+ }
168
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $identifier)) {
169
+ throw new InvalidArgumentException(
170
+ $identifier . ' is an invalid paypal account ' . $identifierType . '.'
171
+ );
172
+ }
173
+ }
174
+ }
lib/Braintree/PaymentInstrumentType.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class Braintree_PaymentInstrumentType
4
+ {
5
+ const PAYPAL_ACCOUNT = 'paypal_account';
6
+ const COINBASE_ACCOUNT = 'coinbase_account';
7
+ const SEPA_BANK_ACCOUNT = 'sepa_bank_account';
8
+ const CREDIT_CARD = 'credit_card';
9
+ }
lib/Braintree/PaymentMethod.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PaymentMethod module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Braintree PaymentMethods
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ */
21
+ class Braintree_PaymentMethod extends Braintree
22
+ {
23
+ // static methods redirecting to gateway
24
+
25
+ public static function create($attribs)
26
+ {
27
+ return Braintree_Configuration::gateway()->paymentMethod()->create($attribs);
28
+ }
29
+
30
+ public static function find($token)
31
+ {
32
+ return Braintree_Configuration::gateway()->paymentMethod()->find($token);
33
+ }
34
+
35
+ public static function update($token, $attribs)
36
+ {
37
+ return Braintree_Configuration::gateway()->paymentMethod()->update($token, $attribs);
38
+ }
39
+
40
+ public static function delete($token)
41
+ {
42
+ return Braintree_Configuration::gateway()->paymentMethod()->delete($token);
43
+ }
44
+ }
lib/Braintree/PaymentMethodGateway.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PaymentMethodGateway module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Braintree PaymentMethods
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ */
21
+ class Braintree_PaymentMethodGateway
22
+ {
23
+ private $_gateway;
24
+ private $_config;
25
+ private $_http;
26
+
27
+ public function __construct($gateway)
28
+ {
29
+ $this->_gateway = $gateway;
30
+ $this->_config = $gateway->config;
31
+ $this->_http = new Braintree_Http($gateway->config);
32
+ }
33
+
34
+
35
+ public function create($attribs)
36
+ {
37
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
38
+ return $this->_doCreate('/payment_methods', array('payment_method' => $attribs));
39
+ }
40
+
41
+ /**
42
+ * find a PaymentMethod by token
43
+ *
44
+ * @access public
45
+ * @param string $token payment method unique id
46
+ * @return object Braintree_CreditCard or Braintree_PayPalAccount
47
+ * @throws Braintree_Exception_NotFound
48
+ */
49
+ public function find($token)
50
+ {
51
+ $this->_validateId($token);
52
+ try {
53
+ $path = $this->_config->merchantPath() . '/payment_methods/any/' . $token;
54
+ $response = $this->_http->get($path);
55
+ if (isset($response['creditCard'])) {
56
+ return Braintree_CreditCard::factory($response['creditCard']);
57
+ } else if (isset($response['paypalAccount'])) {
58
+ return Braintree_PayPalAccount::factory($response['paypalAccount']);
59
+ } else if (isset($response['coinbaseAccount'])) {
60
+ return Braintree_CoinbaseAccount::factory($response['coinbaseAccount']);
61
+ } else if (isset($response['applePayCard'])) {
62
+ return Braintree_ApplePayCard::factory($response['applePayCard']);
63
+ } else if (is_array($response)) {
64
+ return Braintree_UnknownPaymentMethod::factory($response);
65
+ }
66
+ } catch (Braintree_Exception_NotFound $e) {
67
+ throw new Braintree_Exception_NotFound(
68
+ 'payment method with token ' . $token . ' not found'
69
+ );
70
+ }
71
+
72
+ }
73
+
74
+ public function update($token, $attribs)
75
+ {
76
+ Braintree_Util::verifyKeys(self::updateSignature(), $attribs);
77
+ return $this->_doUpdate('/payment_methods/any/' . $token, array('payment_method' => $attribs));
78
+ }
79
+
80
+ public function delete($token)
81
+ {
82
+ $this->_validateId($token);
83
+ $path = $this->_config->merchantPath() . '/payment_methods/any/' . $token;
84
+ $this->_http->delete($path);
85
+ return new Braintree_Result_Successful();
86
+ }
87
+
88
+ private static function baseSignature($options)
89
+ {
90
+ $billingAddressSignature = Braintree_AddressGateway::createSignature();
91
+ return array(
92
+ 'customerId',
93
+ 'paymentMethodNonce',
94
+ 'token',
95
+ 'billingAddressId',
96
+ 'deviceData',
97
+ array('options' => $options),
98
+ array('billingAddress' => $billingAddressSignature)
99
+ );
100
+ }
101
+
102
+ public static function createSignature()
103
+ {
104
+ $options = array(
105
+ 'makeDefault',
106
+ 'verifyCard',
107
+ 'failOnDuplicatePaymentMethod',
108
+ 'verificationMerchantAccountId'
109
+ );
110
+ $signature = self::baseSignature($options);
111
+ return $signature;
112
+ }
113
+
114
+ public static function updateSignature()
115
+ {
116
+ $billingAddressSignature = Braintree_AddressGateway::updateSignature();
117
+ array_push($billingAddressSignature, array(
118
+ 'options' => array(
119
+ 'updateExisting'
120
+ )
121
+ ));
122
+ return array(
123
+ 'billingAddressId',
124
+ 'cardholderName',
125
+ 'cvv',
126
+ 'deviceSessionId',
127
+ 'expirationDate',
128
+ 'expirationMonth',
129
+ 'expirationYear',
130
+ 'number',
131
+ 'token',
132
+ 'venmoSdkPaymentMethodCode',
133
+ 'deviceData',
134
+ 'fraudMerchantId',
135
+ 'paymentMethodNonce',
136
+ array('options' => array(
137
+ 'makeDefault',
138
+ 'verificationMerchantAccountId',
139
+ 'verifyCard',
140
+ 'venmoSdkSession'
141
+ )),
142
+ array('billingAddress' => $billingAddressSignature)
143
+ );
144
+ }
145
+
146
+ /**
147
+ * sends the create request to the gateway
148
+ *
149
+ * @ignore
150
+ * @param string $subPath
151
+ * @param array $params
152
+ * @return mixed
153
+ */
154
+ public function _doCreate($subPath, $params)
155
+ {
156
+ $fullPath = $this->_config->merchantPath() . $subPath;
157
+ $response = $this->_http->post($fullPath, $params);
158
+
159
+ return $this->_verifyGatewayResponse($response);
160
+ }
161
+
162
+ /**
163
+ * sends the update request to the gateway
164
+ *
165
+ * @ignore
166
+ * @param string $subPath
167
+ * @param array $params
168
+ * @return mixed
169
+ */
170
+ public function _doUpdate($subPath, $params)
171
+ {
172
+ $fullPath = $this->_config->merchantPath() . $subPath;
173
+ $response = $this->_http->put($fullPath, $params);
174
+
175
+ return $this->_verifyGatewayResponse($response);
176
+ }
177
+
178
+ /**
179
+ * generic method for validating incoming gateway responses
180
+ *
181
+ * creates a new Braintree_CreditCard or Braintree_PayPalAccount object
182
+ * and encapsulates it inside a Braintree_Result_Successful object, or
183
+ * encapsulates a Braintree_Errors object inside a Result_Error
184
+ * alternatively, throws an Unexpected exception if the response is invalid.
185
+ *
186
+ * @ignore
187
+ * @param array $response gateway response values
188
+ * @return object Result_Successful or Result_Error
189
+ * @throws Braintree_Exception_Unexpected
190
+ */
191
+ private function _verifyGatewayResponse($response)
192
+ {
193
+ if (isset($response['creditCard'])) {
194
+ // return a populated instance of Braintree_CreditCard
195
+ return new Braintree_Result_Successful(
196
+ Braintree_CreditCard::factory($response['creditCard']),
197
+ "paymentMethod"
198
+ );
199
+ } else if (isset($response['paypalAccount'])) {
200
+ // return a populated instance of Braintree_PayPalAccount
201
+ return new Braintree_Result_Successful(
202
+ Braintree_PayPalAccount::factory($response['paypalAccount']),
203
+ "paymentMethod"
204
+ );
205
+ } else if (isset($response['coinbaseAccount'])) {
206
+ // return a populated instance of Braintree_CoinbaseAccount
207
+ return new Braintree_Result_Successful(
208
+ Braintree_CoinbaseAccount::factory($response['coinbaseAccount']),
209
+ "paymentMethod"
210
+ );
211
+ } else if (isset($response['applePayCard'])) {
212
+ // return a populated instance of Braintree_ApplePayCard
213
+ return new Braintree_Result_Successful(
214
+ Braintree_ApplePayCard::factory($response['applePayCard']),
215
+ "paymentMethod"
216
+ );
217
+ } else if (isset($response['apiErrorResponse'])) {
218
+ return new Braintree_Result_Error($response['apiErrorResponse']);
219
+ } else if (is_array($response)) {
220
+ return new Braintree_Result_Successful(
221
+ Braintree_UnknownPaymentMethod::factory($response),
222
+ "paymentMethod"
223
+ );
224
+ } else {
225
+ throw new Braintree_Exception_Unexpected(
226
+ 'Expected payment method or apiErrorResponse'
227
+ );
228
+ }
229
+ }
230
+
231
+ /**
232
+ * verifies that a valid payment method identifier is being used
233
+ * @ignore
234
+ * @param string $identifier
235
+ * @param Optional $string $identifierType type of identifier supplied, default 'token'
236
+ * @throws InvalidArgumentException
237
+ */
238
+ private function _validateId($identifier = null, $identifierType = 'token')
239
+ {
240
+ if (empty($identifier)) {
241
+ throw new InvalidArgumentException(
242
+ 'expected payment method id to be set'
243
+ );
244
+ }
245
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $identifier)) {
246
+ throw new InvalidArgumentException(
247
+ $identifier . ' is an invalid payment method ' . $identifierType . '.'
248
+ );
249
+ }
250
+ }
251
+ }
lib/Braintree/PaymentMethodNonce.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PaymentMethodNonce module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Braintree PaymentMethodNonces
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ */
21
+ class Braintree_PaymentMethodNonce extends Braintree
22
+ {
23
+ // static methods redirecting to gateway
24
+
25
+ public static function create($token)
26
+ {
27
+ return Braintree_Configuration::gateway()->paymentMethodNonce()->create($token);
28
+ }
29
+
30
+ public static function factory($attributes)
31
+ {
32
+ $defaultAttributes = array(
33
+ 'nonce' => '',
34
+ );
35
+
36
+ $instance = new self();
37
+ $instance->_initialize(array_merge($defaultAttributes, $attributes));
38
+ return $instance;
39
+ }
40
+
41
+ protected function _initialize($nonceAttributes)
42
+ {
43
+ $this->_attributes = $nonceAttributes;
44
+ $this->_set('nonce', $nonceAttributes['nonce']);
45
+ }
46
+ }
lib/Braintree/PaymentMethodNonceGateway.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree PaymentMethodNonceGateway module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Braintree PaymentMethodNonces
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ */
21
+ class Braintree_PaymentMethodNonceGateway
22
+ {
23
+ private $_gateway;
24
+ private $_config;
25
+ private $_http;
26
+
27
+ public function __construct($gateway)
28
+ {
29
+ $this->_gateway = $gateway;
30
+ $this->_config = $gateway->config;
31
+ $this->_http = new Braintree_Http($gateway->config);
32
+ }
33
+
34
+
35
+ public function create($token)
36
+ {
37
+ $subPath = '/payment_methods/' . $token . '/nonces';
38
+ $fullPath = $this->_config->merchantPath() . $subPath;
39
+ $response = $this->_http->post($fullPath);
40
+
41
+ return new Braintree_Result_Successful(
42
+ Braintree_PaymentMethodNonce::factory($response['paymentMethodNonce']),
43
+ "paymentMethodNonce"
44
+ );
45
+ }
46
+ }
lib/Braintree/Plan.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Plan extends Braintree
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self();
7
+ $instance->_initialize($attributes);
8
+
9
+ return $instance;
10
+ }
11
+
12
+ protected function _initialize($attributes)
13
+ {
14
+ $this->_attributes = $attributes;
15
+
16
+ $addOnArray = array();
17
+ if (isset($attributes['addOns'])) {
18
+ foreach ($attributes['addOns'] AS $addOn) {
19
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
20
+ }
21
+ }
22
+ $this->_attributes['addOns'] = $addOnArray;
23
+
24
+ $discountArray = array();
25
+ if (isset($attributes['discounts'])) {
26
+ foreach ($attributes['discounts'] AS $discount) {
27
+ $discountArray[] = Braintree_Discount::factory($discount);
28
+ }
29
+ }
30
+ $this->_attributes['discounts'] = $discountArray;
31
+
32
+ $planArray = array();
33
+ if (isset($attributes['plans'])) {
34
+ foreach ($attributes['plans'] AS $plan) {
35
+ $planArray[] = Braintree_Plan::factory($plan);
36
+ }
37
+ }
38
+ $this->_attributes['plans'] = $planArray;
39
+ }
40
+
41
+
42
+ // static methods redirecting to gateway
43
+
44
+ public static function all()
45
+ {
46
+ return Braintree_Configuration::gateway()->plan()->all();
47
+ }
48
+ }
lib/Braintree/PlanGateway.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_PlanGateway
3
+ {
4
+ private $_gateway;
5
+ private $_config;
6
+ private $_http;
7
+
8
+ public function __construct($gateway)
9
+ {
10
+ $this->_gateway = $gateway;
11
+ $this->_config = $gateway->config;
12
+ $this->_http = new Braintree_Http($gateway->config);
13
+ }
14
+
15
+ public function all()
16
+ {
17
+ $path = $this->_config->merchantPath() . '/plans';
18
+ $response = $this->_http->get($path);
19
+ if (key_exists('plans', $response)){
20
+ $plans = array("plan" => $response['plans']);
21
+ } else {
22
+ $plans = array("plan" => array());
23
+ }
24
+
25
+ return Braintree_Util::extractAttributeAsArray(
26
+ $plans,
27
+ 'plan'
28
+ );
29
+ }
30
+ }
lib/Braintree/RangeNode.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_RangeNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerms = array();
9
+ }
10
+
11
+ function greaterThanOrEqualTo($value)
12
+ {
13
+ $this->searchTerms['min'] = $value;
14
+ return $this;
15
+ }
16
+
17
+ function lessThanOrEqualTo($value)
18
+ {
19
+ $this->searchTerms['max'] = $value;
20
+ return $this;
21
+ }
22
+
23
+ function is($value)
24
+ {
25
+ $this->searchTerms['is'] = $value;
26
+ return $this;
27
+ }
28
+
29
+ function between($min, $max)
30
+ {
31
+ return $this->greaterThanOrEqualTo($min)->lessThanOrEqualTo($max);
32
+ }
33
+
34
+ function toParam()
35
+ {
36
+ return $this->searchTerms;
37
+ }
38
+ }
lib/Braintree/ResourceCollection.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree ResourceCollection
4
+ * ResourceCollection is a container object for result data
5
+ *
6
+ * stores and retrieves search results and aggregate data
7
+ *
8
+ * example:
9
+ * <code>
10
+ * $result = Braintree_Customer::all();
11
+ *
12
+ * foreach($result as $transaction) {
13
+ * print_r($transaction->id);
14
+ * }
15
+ * </code>
16
+ *
17
+ * @package Braintree
18
+ * @subpackage Utility
19
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
20
+ */
21
+ class Braintree_ResourceCollection implements Iterator
22
+ {
23
+ private $_index;
24
+ private $_batchIndex;
25
+ private $_items;
26
+ private $_pageSize;
27
+ private $_pager;
28
+
29
+ /**
30
+ * set up the resource collection
31
+ *
32
+ * expects an array of attributes with literal keys
33
+ *
34
+ * @param array $attributes
35
+ * @param array $pagerAttribs
36
+ */
37
+ public function __construct($response, $pager)
38
+ {
39
+ $this->_pageSize = $response["searchResults"]["pageSize"];
40
+ $this->_ids = $response["searchResults"]["ids"];
41
+ $this->_pager = $pager;
42
+ }
43
+
44
+ /**
45
+ * returns the current item when iterating with foreach
46
+ */
47
+ public function current()
48
+ {
49
+ return $this->_items[$this->_index];
50
+ }
51
+
52
+ /**
53
+ * returns the first item in the collection
54
+ *
55
+ * @return mixed
56
+ */
57
+ public function firstItem()
58
+ {
59
+ $ids = $this->_ids;
60
+ $page = $this->_getPage(array($ids[0]));
61
+ return $page[0];
62
+ }
63
+
64
+ public function key()
65
+ {
66
+ return null;
67
+ }
68
+
69
+ /**
70
+ * advances to the next item in the collection when iterating with foreach
71
+ */
72
+ public function next()
73
+ {
74
+ ++$this->_index;
75
+ }
76
+
77
+ /**
78
+ * rewinds the testIterateOverResults collection to the first item when iterating with foreach
79
+ */
80
+ public function rewind()
81
+ {
82
+ $this->_batchIndex = 0;
83
+ $this->_getNextPage();
84
+ }
85
+
86
+ /**
87
+ * returns whether the current item is valid when iterating with foreach
88
+ */
89
+ public function valid()
90
+ {
91
+ if ($this->_index == count($this->_items) && $this->_batchIndex < count($this->_ids)) {
92
+ $this->_getNextPage();
93
+ }
94
+
95
+ if ($this->_index < count($this->_items)) {
96
+ return true;
97
+ } else {
98
+ return false;
99
+ }
100
+ }
101
+
102
+ public function maximumCount()
103
+ {
104
+ return count($this->_ids);
105
+ }
106
+
107
+ private function _getNextPage()
108
+ {
109
+ if (empty($this->_ids))
110
+ {
111
+ $this->_items = array();
112
+ }
113
+ else
114
+ {
115
+ $this->_items = $this->_getPage(array_slice($this->_ids, $this->_batchIndex, $this->_pageSize));
116
+ $this->_batchIndex += $this->_pageSize;
117
+ $this->_index = 0;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * requests the next page of results for the collection
123
+ *
124
+ * @return none
125
+ */
126
+ private function _getPage($ids)
127
+ {
128
+ $object = $this->_pager['object'];
129
+ $method = $this->_pager['method'];
130
+ $methodArgs = array();
131
+ foreach ($this->_pager['methodArgs'] as $arg) {
132
+ array_push($methodArgs, $arg);
133
+ }
134
+ array_push($methodArgs, $ids);
135
+
136
+ return call_user_func_array(
137
+ array($object, $method),
138
+ $methodArgs
139
+ );
140
+ }
141
+ }
lib/Braintree/Result/CreditCardVerification.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Credit Card Verification Result
4
+ *
5
+ * This object is returned as part of an Error Result; it provides
6
+ * access to the credit card verification data from the gateway
7
+ *
8
+ *
9
+ * @package Braintree
10
+ * @subpackage Result
11
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
12
+ *
13
+ * @property-read string $avsErrorResponseCode
14
+ * @property-read string $avsPostalCodeResponseCode
15
+ * @property-read string $avsStreetAddressResponseCode
16
+ * @property-read string $cvvResponseCode
17
+ * @property-read string $status
18
+ *
19
+ */
20
+ class Braintree_Result_CreditCardVerification
21
+ {
22
+ // Status
23
+ const FAILED = 'failed';
24
+ const GATEWAY_REJECTED = 'gateway_rejected';
25
+ const PROCESSOR_DECLINED = 'processor_declined';
26
+ const VERIFIED = 'verified';
27
+
28
+ private $_attributes;
29
+ private $_avsErrorResponseCode;
30
+ private $_avsPostalCodeResponseCode;
31
+ private $_avsStreetAddressResponseCode;
32
+ private $_cvvResponseCode;
33
+ private $_gatewayRejectionReason;
34
+ private $_status;
35
+
36
+ /**
37
+ * @ignore
38
+ */
39
+ public function __construct($attributes)
40
+ {
41
+ $this->_initializeFromArray($attributes);
42
+ }
43
+
44
+ /**
45
+ * initializes instance properties from the keys/values of an array
46
+ * @ignore
47
+ * @access protected
48
+ * @param <type> $aAttribs array of properties to set - single level
49
+ * @return none
50
+ */
51
+ private function _initializeFromArray($attributes)
52
+ {
53
+ if(isset($attributes['riskData']))
54
+ {
55
+ $attributes['riskData'] = Braintree_RiskData::factory($attributes['riskData']);
56
+ }
57
+
58
+ $this->_attributes = $attributes;
59
+ foreach($attributes AS $name => $value) {
60
+ $varName = "_$name";
61
+ $this->$varName = $value;
62
+ }
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @ignore
68
+ */
69
+ public function __get($name)
70
+ {
71
+ $varName = "_$name";
72
+ return isset($this->$varName) ? $this->$varName : null;
73
+ }
74
+
75
+ /**
76
+ * returns a string representation of the customer
77
+ * @return string
78
+ */
79
+ public function __toString()
80
+ {
81
+ return __CLASS__ . '[' .
82
+ Braintree_Util::attributesToString($this->_attributes) .']';
83
+ }
84
+ }
lib/Braintree/Result/Error.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Error Result
4
+ *
5
+ * An Error Result will be returned from gateway methods when
6
+ * the gateway responds with an error. It will provide access
7
+ * to the original request.
8
+ * For example, when voiding a transaction, Error Result will
9
+ * respond to the void request if it failed:
10
+ *
11
+ * <code>
12
+ * $result = Braintree_Transaction::void('abc123');
13
+ * if ($result->success) {
14
+ * // Successful Result
15
+ * } else {
16
+ * // Braintree_Result_Error
17
+ * }
18
+ * </code>
19
+ *
20
+ * @package Braintree
21
+ * @subpackage Result
22
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
23
+ *
24
+ * @property-read array $params original passed params
25
+ * @property-read object $errors Braintree_Error_ErrorCollection
26
+ * @property-read object $creditCardVerification credit card verification data
27
+ */
28
+ class Braintree_Result_Error extends Braintree
29
+ {
30
+ /**
31
+ *
32
+ * @var boolean always false
33
+ */
34
+ public $success = false;
35
+
36
+ /**
37
+ * return original value for a field
38
+ * For example, if a user tried to submit 'invalid-email' in the html field transaction[customer][email],
39
+ * $result->valueForHtmlField("transaction[customer][email]") would yield "invalid-email"
40
+ *
41
+ * @param string $field
42
+ * @return string
43
+ */
44
+ public function valueForHtmlField($field)
45
+ {
46
+ $pieces = preg_split("/[\[\]]+/", $field, 0, PREG_SPLIT_NO_EMPTY);
47
+ $params = $this->params;
48
+ foreach(array_slice($pieces, 0, -1) as $key) {
49
+ $params = $params[Braintree_Util::delimiterToCamelCase($key)];
50
+ }
51
+ if ($key != 'custom_fields') {
52
+ $finalKey = Braintree_Util::delimiterToCamelCase(end($pieces));
53
+ } else {
54
+ $finalKey = end($pieces);
55
+ }
56
+ $fieldValue = isset($params[$finalKey]) ? $params[$finalKey] : null;
57
+ return $fieldValue;
58
+ }
59
+
60
+ /**
61
+ * overrides default constructor
62
+ * @ignore
63
+ * @param array $response gateway response array
64
+ */
65
+ public function __construct($response)
66
+ {
67
+ $this->_attributes = $response;
68
+ $this->_set('errors', new Braintree_Error_ErrorCollection($response['errors']));
69
+
70
+ if(isset($response['verification'])) {
71
+ $this->_set('creditCardVerification', new Braintree_Result_CreditCardVerification($response['verification']));
72
+ } else {
73
+ $this->_set('creditCardVerification', null);
74
+ }
75
+
76
+ if(isset($response['transaction'])) {
77
+ $this->_set('transaction', Braintree_Transaction::factory($response['transaction']));
78
+ } else {
79
+ $this->_set('transaction', null);
80
+ }
81
+
82
+ if(isset($response['subscription'])) {
83
+ $this->_set('subscription', Braintree_Subscription::factory($response['subscription']));
84
+ } else {
85
+ $this->_set('subscription', null);
86
+ }
87
+
88
+ if(isset($response['merchantAccount'])) {
89
+ $this->_set('merchantAccount', Braintree_MerchantAccount::factory($response['merchantAccount']));
90
+ } else {
91
+ $this->_set('merchantAccount', null);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * create a printable representation of the object as:
97
+ * ClassName[property=value, property=value]
98
+ * @ignore
99
+ * @return var
100
+ */
101
+ public function __toString()
102
+ {
103
+ $output = Braintree_Util::attributesToString($this->_attributes);
104
+ if (isset($this->_creditCardVerification)) {
105
+ $output .= sprintf('%s', $this->_creditCardVerification);
106
+ }
107
+ return __CLASS__ .'['.$output.']';
108
+ }
109
+ }
lib/Braintree/Result/Successful.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Successful Result
4
+ *
5
+ * A Successful Result will be returned from gateway methods when
6
+ * validations pass. It will provide access to the created resource.
7
+ *
8
+ * For example, when creating a customer, Braintree_Result_Successful will
9
+ * respond to <b>customer</b> like so:
10
+ *
11
+ * <code>
12
+ * $result = Braintree_Customer::create(array('first_name' => "John"));
13
+ * if ($result->success) {
14
+ * // Braintree_Result_Successful
15
+ * echo "Created customer {$result->customer->id}";
16
+ * } else {
17
+ * // Braintree_Result_Error
18
+ * }
19
+ * </code>
20
+ *
21
+ *
22
+ * @package Braintree
23
+ * @subpackage Result
24
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
25
+ */
26
+ class Braintree_Result_Successful extends Braintree_Instance
27
+ {
28
+ /**
29
+ *
30
+ * @var boolean always true
31
+ */
32
+ public $success = true;
33
+ /**
34
+ *
35
+ * @var string stores the internal name of the object providing access to
36
+ */
37
+ private $_returnObjectName;
38
+
39
+ /**
40
+ * @ignore
41
+ * @param string $classToReturn name of class to instantiate
42
+ */
43
+ public function __construct($objToReturn = null, $propertyName = null)
44
+ {
45
+ $this->_attributes = array();
46
+
47
+ if(!empty($objToReturn)) {
48
+
49
+ if(empty($propertyName)) {
50
+ $propertyName = Braintree_Util::cleanClassName(
51
+ get_class($objToReturn)
52
+ );
53
+ }
54
+
55
+ // save the name for indirect access
56
+ $this->_returnObjectName = $propertyName;
57
+
58
+ // create the property!
59
+ $this->$propertyName = $objToReturn;
60
+ }
61
+ }
62
+
63
+ /**
64
+ *
65
+ * @ignore
66
+ * @return string string representation of the object's structure
67
+ */
68
+ public function __toString()
69
+ {
70
+ $returnObject = $this->_returnObjectName;
71
+ return __CLASS__ . '['.$this->$returnObject->__toString().']';
72
+ }
73
+
74
+ }
lib/Braintree/RiskData.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_RiskData extends Braintree
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self();
7
+ $instance->_initialize($attributes);
8
+
9
+ return $instance;
10
+ }
11
+
12
+ protected function _initialize($attributes)
13
+ {
14
+ $this->_attributes = $attributes;
15
+ }
16
+
17
+ /**
18
+ * returns a string representation of the risk data
19
+ * @return string
20
+ */
21
+ public function __toString()
22
+ {
23
+ return __CLASS__ . '[' .
24
+ Braintree_Util::attributesToString($this->_attributes) .']';
25
+ }
26
+
27
+ }
lib/Braintree/SettlementBatchSummary.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_SettlementBatchSummary extends Braintree
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self();
7
+ $instance->_initialize($attributes);
8
+ return $instance;
9
+ }
10
+
11
+ /**
12
+ * @ignore
13
+ */
14
+ protected function _initialize($attributes)
15
+ {
16
+ $this->_attributes = $attributes;
17
+ }
18
+
19
+ public function records()
20
+ {
21
+ return $this->_attributes['records'];
22
+ }
23
+
24
+
25
+ // static methods redirecting to gateway
26
+
27
+ public static function generate($settlement_date, $groupByCustomField = NULL)
28
+ {
29
+ return Braintree_Configuration::gateway()->settlementBatchSummary()->generate($settlement_date, $groupByCustomField);
30
+ }
31
+ }
lib/Braintree/SettlementBatchSummaryGateway.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_SettlementBatchSummaryGateway
3
+ {
4
+ private $_gateway;
5
+ private $_config;
6
+ private $_http;
7
+
8
+ public function __construct($gateway)
9
+ {
10
+ $this->_gateway = $gateway;
11
+ $this->_config = $gateway->config;
12
+ $this->_http = new Braintree_Http($gateway->config);
13
+ }
14
+
15
+ public function generate($settlement_date, $groupByCustomField = NULL)
16
+ {
17
+ $criteria = array('settlement_date' => $settlement_date);
18
+ if (isset($groupByCustomField))
19
+ {
20
+ $criteria['group_by_custom_field'] = $groupByCustomField;
21
+ }
22
+ $params = array('settlement_batch_summary' => $criteria);
23
+ $path = $this->_config->merchantPath() . '/settlement_batch_summary';
24
+ $response = $this->_http->post($path, $params);
25
+
26
+ if (isset($groupByCustomField))
27
+ {
28
+ $response['settlementBatchSummary']['records'] = $this->_underscoreCustomField(
29
+ $groupByCustomField,
30
+ $response['settlementBatchSummary']['records']
31
+ );
32
+ }
33
+
34
+ return $this->_verifyGatewayResponse($response);
35
+ }
36
+
37
+ private function _underscoreCustomField($groupByCustomField, $records)
38
+ {
39
+ $updatedRecords = array();
40
+
41
+ foreach ($records as $record)
42
+ {
43
+ $camelized = Braintree_Util::delimiterToCamelCase($groupByCustomField);
44
+ $record[$groupByCustomField] = $record[$camelized];
45
+ unset($record[$camelized]);
46
+ $updatedRecords[] = $record;
47
+ }
48
+
49
+ return $updatedRecords;
50
+ }
51
+
52
+ private function _verifyGatewayResponse($response)
53
+ {
54
+ if (isset($response['settlementBatchSummary'])) {
55
+ return new Braintree_Result_Successful(
56
+ Braintree_SettlementBatchSummary::factory($response['settlementBatchSummary'])
57
+ );
58
+ } else if (isset($response['apiErrorResponse'])) {
59
+ return new Braintree_Result_Error($response['apiErrorResponse']);
60
+ } else {
61
+ throw new Braintree_Exception_Unexpected(
62
+ "Expected settlementBatchSummary or apiErrorResponse"
63
+ );
64
+ }
65
+ }
66
+ }
lib/Braintree/SignatureService.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_SignatureService
4
+ {
5
+
6
+ public function __construct($key, $digest)
7
+ {
8
+ $this->key = $key;
9
+ $this->digest = $digest;
10
+ }
11
+
12
+ public function sign($payload)
13
+ {
14
+ return $this->hash($payload) . "|" . $payload;
15
+ }
16
+
17
+ public function hash($data)
18
+ {
19
+ return call_user_func($this->digest, $this->key, $data);
20
+ }
21
+
22
+ }
lib/Braintree/Subscription.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Subscription module
4
+ *
5
+ * <b>== More information ==</b>
6
+ *
7
+ * For more detailed information on Subscriptions, see {@link http://www.braintreepayments.com/gateway/subscription-api http://www.braintreepaymentsolutions.com/gateway/subscription-api}
8
+ *
9
+ * PHP Version 5
10
+ *
11
+ * @package Braintree
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_Subscription extends Braintree
15
+ {
16
+ const ACTIVE = 'Active';
17
+ const CANCELED = 'Canceled';
18
+ const EXPIRED = 'Expired';
19
+ const PAST_DUE = 'Past Due';
20
+ const PENDING = 'Pending';
21
+
22
+ // Subscription Sources
23
+ const API = 'api';
24
+ const CONTROL_PANEL = 'control_panel';
25
+ const RECURRING = 'recurring';
26
+
27
+ /**
28
+ * @ignore
29
+ */
30
+ public static function factory($attributes)
31
+ {
32
+ $instance = new self();
33
+ $instance->_initialize($attributes);
34
+
35
+ return $instance;
36
+ }
37
+
38
+ /**
39
+ * @ignore
40
+ */
41
+ protected function _initialize($attributes)
42
+ {
43
+ $this->_attributes = $attributes;
44
+
45
+ $addOnArray = array();
46
+ if (isset($attributes['addOns'])) {
47
+ foreach ($attributes['addOns'] AS $addOn) {
48
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
49
+ }
50
+ }
51
+ $this->_attributes['addOns'] = $addOnArray;
52
+
53
+ $discountArray = array();
54
+ if (isset($attributes['discounts'])) {
55
+ foreach ($attributes['discounts'] AS $discount) {
56
+ $discountArray[] = Braintree_Discount::factory($discount);
57
+ }
58
+ }
59
+ $this->_attributes['discounts'] = $discountArray;
60
+
61
+ if (isset($attributes['descriptor'])) {
62
+ $this->_set('descriptor', new Braintree_Descriptor($attributes['descriptor']));
63
+ }
64
+
65
+ $statusHistory = array();
66
+ if (isset($attributes['statusHistory'])) {
67
+ foreach ($attributes['statusHistory'] AS $history) {
68
+ $statusHistory[] = new Braintree_Subscription_StatusDetails($history);
69
+ }
70
+ }
71
+ $this->_attributes['statusHistory'] = $statusHistory;
72
+
73
+ $transactionArray = array();
74
+ if (isset($attributes['transactions'])) {
75
+ foreach ($attributes['transactions'] AS $transaction) {
76
+ $transactionArray[] = Braintree_Transaction::factory($transaction);
77
+ }
78
+ }
79
+ $this->_attributes['transactions'] = $transactionArray;
80
+ }
81
+
82
+ /**
83
+ * returns a string representation of the customer
84
+ * @return string
85
+ */
86
+ public function __toString()
87
+ {
88
+ $excludedAttributes = array('statusHistory');
89
+
90
+ $displayAttributes = array();
91
+ foreach($this->_attributes as $key => $val) {
92
+ if (!in_array($key, $excludedAttributes)) {
93
+ $displayAttributes[$key] = $val;
94
+ }
95
+ }
96
+
97
+ return __CLASS__ . '[' .
98
+ Braintree_Util::attributesToString($displayAttributes) .']';
99
+ }
100
+
101
+
102
+ // static methods redirecting to gateway
103
+
104
+ public static function create($attributes)
105
+ {
106
+ return Braintree_Configuration::gateway()->subscription()->create($attributes);
107
+ }
108
+
109
+ public static function find($id)
110
+ {
111
+ return Braintree_Configuration::gateway()->subscription()->find($id);
112
+ }
113
+
114
+ public static function search($query)
115
+ {
116
+ return Braintree_Configuration::gateway()->subscription()->search($query);
117
+ }
118
+
119
+ public static function fetch($query, $ids)
120
+ {
121
+ return Braintree_Configuration::gateway()->subscription()->fetch($query, $ids);
122
+ }
123
+
124
+ public static function update($subscriptionId, $attributes)
125
+ {
126
+ return Braintree_Configuration::gateway()->subscription()->update($subscriptionId, $attributes);
127
+ }
128
+
129
+ public static function retryCharge($subscriptionId, $amount = null)
130
+ {
131
+ return Braintree_Configuration::gateway()->subscription()->retryCharge($subscriptionId, $amount);
132
+ }
133
+
134
+ public static function cancel($subscriptionId)
135
+ {
136
+ return Braintree_Configuration::gateway()->subscription()->cancel($subscriptionId);
137
+ }
138
+ }
lib/Braintree/Subscription/StatusDetails.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Status details from a subscription
4
+ * Creates an instance of StatusDetails, as part of a subscription response
5
+ *
6
+ * @package Braintree
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ *
9
+ * @property-read string $price
10
+ * @property-read string $balance
11
+ * @property-read string $status
12
+ * @property-read string $timestamp
13
+ * @property-read string $subscriptionSource
14
+ * @property-read string $user
15
+ * @uses Braintree_Instance inherits methods
16
+ */
17
+ class Braintree_Subscription_StatusDetails extends Braintree_Instance
18
+ {
19
+ }
lib/Braintree/SubscriptionGateway.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree SubscriptionGateway module
4
+ *
5
+ * <b>== More information ==</b>
6
+ *
7
+ * For more detailed information on Subscriptions, see {@link http://www.braintreepayments.com/gateway/subscription-api http://www.braintreepaymentsolutions.com/gateway/subscription-api}
8
+ *
9
+ * PHP Version 5
10
+ *
11
+ * @package Braintree
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_SubscriptionGateway
15
+ {
16
+ private $_gateway;
17
+ private $_config;
18
+ private $_http;
19
+
20
+ public function __construct($gateway)
21
+ {
22
+ $this->_gateway = $gateway;
23
+ $this->_config = $gateway->config;
24
+ $this->_http = new Braintree_Http($gateway->config);
25
+ }
26
+
27
+ public function create($attributes)
28
+ {
29
+ Braintree_Util::verifyKeys(self::_createSignature(), $attributes);
30
+ $path = $this->_config->merchantPath() . '/subscriptions';
31
+ $response = $this->_http->post($path, array('subscription' => $attributes));
32
+ return $this->_verifyGatewayResponse($response);
33
+ }
34
+
35
+ public function find($id)
36
+ {
37
+ $this->_validateId($id);
38
+
39
+ try {
40
+ $path = $this->_config->merchantPath() . '/subscriptions/' . $id;
41
+ $response = $this->_http->get($path);
42
+ return Braintree_Subscription::factory($response['subscription']);
43
+ } catch (Braintree_Exception_NotFound $e) {
44
+ throw new Braintree_Exception_NotFound('subscription with id ' . $id . ' not found');
45
+ }
46
+
47
+ }
48
+
49
+ public function search($query)
50
+ {
51
+ $criteria = array();
52
+ foreach ($query as $term) {
53
+ $criteria[$term->name] = $term->toparam();
54
+ }
55
+
56
+
57
+ $path = $this->_config->merchantPath() . '/subscriptions/advanced_search_ids';
58
+ $response = $this->_http->post($path, array('search' => $criteria));
59
+ $pager = array(
60
+ 'object' => $this,
61
+ 'method' => 'fetch',
62
+ 'methodArgs' => array($query)
63
+ );
64
+
65
+ return new Braintree_ResourceCollection($response, $pager);
66
+ }
67
+
68
+ public function fetch($query, $ids)
69
+ {
70
+ $criteria = array();
71
+ foreach ($query as $term) {
72
+ $criteria[$term->name] = $term->toparam();
73
+ }
74
+ $criteria["ids"] = Braintree_SubscriptionSearch::ids()->in($ids)->toparam();
75
+ $path = $this->_config->merchantPath() . '/subscriptions/advanced_search';
76
+ $response = $this->_http->post($path, array('search' => $criteria));
77
+
78
+ return Braintree_Util::extractAttributeAsArray(
79
+ $response['subscriptions'],
80
+ 'subscription'
81
+ );
82
+ }
83
+
84
+ public function update($subscriptionId, $attributes)
85
+ {
86
+ Braintree_Util::verifyKeys(self::_updateSignature(), $attributes);
87
+ $path = $this->_config->merchantPath() . '/subscriptions/' . $subscriptionId;
88
+ $response = $this->_http->put($path, array('subscription' => $attributes));
89
+ return $this->_verifyGatewayResponse($response);
90
+ }
91
+
92
+ public function retryCharge($subscriptionId, $amount = null)
93
+ {
94
+ $transaction_params = array('type' => Braintree_Transaction::SALE,
95
+ 'subscriptionId' => $subscriptionId);
96
+ if (isset($amount)) {
97
+ $transaction_params['amount'] = $amount;
98
+ }
99
+
100
+ $path = $this->_config->merchantPath() . '/transactions';
101
+ $response = $this->_http->post($path, array('transaction' => $transaction_params));
102
+ return $this->_verifyGatewayResponse($response);
103
+ }
104
+
105
+ public function cancel($subscriptionId)
106
+ {
107
+ $path = $this->_config->merchantPath() . '/subscriptions/' . $subscriptionId . '/cancel';
108
+ $response = $this->_http->put($path);
109
+ return $this->_verifyGatewayResponse($response);
110
+ }
111
+
112
+ private static function _createSignature()
113
+ {
114
+ return array_merge(
115
+ array(
116
+ 'billingDayOfMonth',
117
+ 'firstBillingDate',
118
+ 'createdAt',
119
+ 'updatedAt',
120
+ 'id',
121
+ 'merchantAccountId',
122
+ 'neverExpires',
123
+ 'numberOfBillingCycles',
124
+ 'paymentMethodToken',
125
+ 'paymentMethodNonce',
126
+ 'planId',
127
+ 'price',
128
+ 'trialDuration',
129
+ 'trialDurationUnit',
130
+ 'trialPeriod',
131
+ array('descriptor' => array('name', 'phone', 'url')),
132
+ array('options' => array('doNotInheritAddOnsOrDiscounts', 'startImmediately')),
133
+ ),
134
+ self::_addOnDiscountSignature()
135
+ );
136
+ }
137
+
138
+ private static function _updateSignature()
139
+ {
140
+ return array_merge(
141
+ array(
142
+ 'merchantAccountId', 'numberOfBillingCycles', 'paymentMethodToken', 'planId',
143
+ 'paymentMethodNonce', 'id', 'neverExpires', 'price',
144
+ array('descriptor' => array('name', 'phone', 'url')),
145
+ array('options' => array('prorateCharges', 'replaceAllAddOnsAndDiscounts', 'revertSubscriptionOnProrationFailure')),
146
+ ),
147
+ self::_addOnDiscountSignature()
148
+ );
149
+ }
150
+
151
+ private static function _addOnDiscountSignature()
152
+ {
153
+ return array(
154
+ array(
155
+ 'addOns' => array(
156
+ array('add' => array('amount', 'inheritedFromId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
157
+ array('update' => array('amount', 'existingId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
158
+ array('remove' => array('_anyKey_')),
159
+ )
160
+ ),
161
+ array(
162
+ 'discounts' => array(
163
+ array('add' => array('amount', 'inheritedFromId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
164
+ array('update' => array('amount', 'existingId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
165
+ array('remove' => array('_anyKey_')),
166
+ )
167
+ )
168
+ );
169
+ }
170
+
171
+ /**
172
+ * @ignore
173
+ */
174
+ private function _validateId($id = null) {
175
+ if (empty($id)) {
176
+ throw new InvalidArgumentException(
177
+ 'expected subscription id to be set'
178
+ );
179
+ }
180
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
181
+ throw new InvalidArgumentException(
182
+ $id . ' is an invalid subscription id.'
183
+ );
184
+ }
185
+ }
186
+
187
+ /**
188
+ * @ignore
189
+ */
190
+ private function _verifyGatewayResponse($response)
191
+ {
192
+ if (isset($response['subscription'])) {
193
+ return new Braintree_Result_Successful(
194
+ Braintree_Subscription::factory($response['subscription'])
195
+ );
196
+ } else if (isset($response['transaction'])) {
197
+ // return a populated instance of Braintree_Transaction, for subscription retryCharge
198
+ return new Braintree_Result_Successful(
199
+ Braintree_Transaction::factory($response['transaction'])
200
+ );
201
+ } else if (isset($response['apiErrorResponse'])) {
202
+ return new Braintree_Result_Error($response['apiErrorResponse']);
203
+ } else {
204
+ throw new Braintree_Exception_Unexpected(
205
+ "Expected subscription, transaction, or apiErrorResponse"
206
+ );
207
+ }
208
+ }
209
+ }
lib/Braintree/SubscriptionSearch.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_SubscriptionSearch
3
+ {
4
+ static function billingCyclesRemaining()
5
+ {
6
+ return new Braintree_RangeNode('billing_cycles_remaining');
7
+ }
8
+
9
+ static function daysPastDue()
10
+ {
11
+ return new Braintree_RangeNode('days_past_due');
12
+ }
13
+
14
+ static function id()
15
+ {
16
+ return new Braintree_TextNode('id');
17
+ }
18
+
19
+ static function inTrialPeriod()
20
+ {
21
+ return new Braintree_MultipleValueNode('in_trial_period', array(true, false));
22
+ }
23
+
24
+ static function merchantAccountId()
25
+ {
26
+ return new Braintree_MultipleValueNode('merchant_account_id');
27
+ }
28
+
29
+ static function nextBillingDate()
30
+ {
31
+ return new Braintree_RangeNode('next_billing_date');
32
+ }
33
+
34
+ static function planId()
35
+ {
36
+ return new Braintree_MultipleValueOrTextNode('plan_id');
37
+ }
38
+
39
+ static function price()
40
+ {
41
+ return new Braintree_RangeNode('price');
42
+ }
43
+
44
+ static function status()
45
+ {
46
+ return new Braintree_MultipleValueNode("status", array(
47
+ Braintree_Subscription::ACTIVE,
48
+ Braintree_Subscription::CANCELED,
49
+ Braintree_Subscription::EXPIRED,
50
+ Braintree_Subscription::PAST_DUE,
51
+ Braintree_Subscription::PENDING
52
+ ));
53
+ }
54
+
55
+ static function transactionId()
56
+ {
57
+ return new Braintree_TextNode('transaction_id');
58
+ }
59
+
60
+ static function ids()
61
+ {
62
+ return new Braintree_MultipleValueNode('ids');
63
+ }
64
+ }
lib/Braintree/Test/CreditCardNumbers.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Credit card information used for testing purposes
5
+ *
6
+ * The constants contained in the Braintree_Test_CreditCardNumbers class provide
7
+ * credit card numbers that should be used when working in the sandbox environment.
8
+ * The sandbox will not accept any credit card numbers other than the ones listed below.
9
+ *
10
+ * @package Braintree
11
+ * @subpackage Test
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_Test_CreditCardNumbers
15
+ {
16
+ public static $amExes = array(
17
+ '378282246310005',
18
+ '371449635398431',
19
+ '378734493671000',
20
+ );
21
+ public static $carteBlanches = array('30569309025904',);
22
+ public static $dinersClubs = array('38520000023237',);
23
+ public static $discoverCards = array(
24
+ '6011111111111117',
25
+ '6011000990139424',
26
+ );
27
+ public static $JCBs = array(
28
+ '3530111333300000',
29
+ '3566002020360505',
30
+ );
31
+
32
+ public static $masterCard = '5555555555554444';
33
+ public static $masterCardInternational = '5105105105105100';
34
+ public static $masterCards = array(
35
+ '5105105105105100',
36
+ '5555555555554444',
37
+ );
38
+
39
+ public static $visa = '4012888888881881';
40
+ public static $visaInternational = '4009348888881881';
41
+ public static $visas = array(
42
+ '4009348888881881',
43
+ '4012888888881881',
44
+ '4111111111111111',
45
+ '4000111111111115',
46
+ );
47
+
48
+ public static $unknowns = array(
49
+ '1000000000000008',
50
+ );
51
+
52
+ public static $failsSandboxVerification = array(
53
+ 'AmEx' => '378734493671000',
54
+ 'Discover' => '6011000990139424',
55
+ 'MasterCard' => '5105105105105100',
56
+ 'Visa' => '4000111111111115',
57
+ );
58
+
59
+
60
+ public static function getAll()
61
+ {
62
+ return array_merge(
63
+ self::$amExes,
64
+ self::$discoverCards,
65
+ self::$masterCards,
66
+ self::$visas
67
+ );
68
+ }
69
+ }
lib/Braintree/Test/MerchantAccount.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Merchant Account constants used for testing purposes
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Test
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Test_MerchantAccount
10
+ {
11
+ public static $approve = "approve_me";
12
+
13
+ public static $insufficientFundsContactUs = "insufficient_funds__contact";
14
+ public static $accountNotAuthorizedContactUs = "account_not_authorized__contact";
15
+ public static $bankRejectedUpdateFundingInformation = "bank_rejected__update";
16
+ public static $bankRejectedNone = "bank_rejected__none";
17
+
18
+
19
+ }
lib/Braintree/Test/Nonces.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Nonces used for testing purposes
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Test
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Nonces used for testing purposes
12
+ *
13
+ * The constants in this class can be used to perform nonce operations
14
+ * with the desired status in the sandbox environment.
15
+ *
16
+ * @package Braintree
17
+ * @subpackage Test
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ */
20
+ class Braintree_Test_Nonces
21
+ {
22
+ public static $transactable = "fake-valid-nonce";
23
+ public static $consumed = "fake-consumed-nonce";
24
+ public static $paypalOneTimePayment = "fake-paypal-one-time-nonce";
25
+ public static $paypalFuturePayment = "fake-paypal-future-nonce";
26
+ public static $applePayVisa = "fake-apple-pay-visa-nonce";
27
+ public static $applePayMasterCard = "fake-apple-pay-visa-nonce";
28
+ public static $applePayAmEx = "fake-apple-pay-amex-nonce";
29
+ public static $abstractTransactable = "fake-abstract-transactable-nonce";
30
+ public static $coinbase = "fake-coinbase-nonce";
31
+ }
lib/Braintree/Test/TransactionAmounts.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Transaction amounts used for testing purposes
5
+ *
6
+ * The constants in this class can be used to create transactions with
7
+ * the desired status in the sandbox environment.
8
+ *
9
+ * @package Braintree
10
+ * @subpackage Test
11
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
12
+ */
13
+ class Braintree_Test_TransactionAmounts
14
+ {
15
+ public static $authorize = '1000.00';
16
+ public static $decline = '2000.00';
17
+ }
lib/Braintree/Test/VenmoSdk.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * VenmoSdk payment method codes used for testing purposes
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Test
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ class Braintree_Test_VenmoSdk
10
+ {
11
+ public static $visaPaymentMethodCode = "stub-4111111111111111";
12
+
13
+ public static function generateTestPaymentMethodCode($number) {
14
+ return "stub-" . $number;
15
+ }
16
+
17
+ public static function getInvalidPaymentMethodCode() {
18
+ return "stub-invalid-payment-method-code";
19
+ }
20
+
21
+ public static function getTestSession() {
22
+ return "stub-session";
23
+ }
24
+
25
+ public static function getInvalidTestSession() {
26
+ return "stub-invalid-session";
27
+ }
28
+ }
lib/Braintree/TextNode.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_TextNode extends Braintree_PartialMatchNode
4
+ {
5
+ function contains($value)
6
+ {
7
+ $this->searchTerms["contains"] = strval($value);
8
+ return $this;
9
+ }
10
+ }
lib/Braintree/Transaction.php ADDED
@@ -0,0 +1,504 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Transaction processor
4
+ * Creates and manages transactions
5
+ *
6
+ * At minimum, an amount, credit card number, and
7
+ * credit card expiration date are required.
8
+ *
9
+ * <b>Minimalistic example:</b>
10
+ * <code>
11
+ * Braintree_Transaction::saleNoValidate(array(
12
+ * 'amount' => '100.00',
13
+ * 'creditCard' => array(
14
+ * 'number' => '5105105105105100',
15
+ * 'expirationDate' => '05/12',
16
+ * ),
17
+ * ));
18
+ * </code>
19
+ *
20
+ * <b>Full example:</b>
21
+ * <code>
22
+ * Braintree_Transaction::saleNoValidate(array(
23
+ * 'amount' => '100.00',
24
+ * 'orderId' => '123',
25
+ * 'channel' => 'MyShoppingCardProvider',
26
+ * 'creditCard' => array(
27
+ * // if token is omitted, the gateway will generate a token
28
+ * 'token' => 'credit_card_123',
29
+ * 'number' => '5105105105105100',
30
+ * 'expirationDate' => '05/2011',
31
+ * 'cvv' => '123',
32
+ * ),
33
+ * 'customer' => array(
34
+ * // if id is omitted, the gateway will generate an id
35
+ * 'id' => 'customer_123',
36
+ * 'firstName' => 'Dan',
37
+ * 'lastName' => 'Smith',
38
+ * 'company' => 'Braintree',
39
+ * 'email' => 'dan@example.com',
40
+ * 'phone' => '419-555-1234',
41
+ * 'fax' => '419-555-1235',
42
+ * 'website' => 'http://braintreepayments.com'
43
+ * ),
44
+ * 'billing' => array(
45
+ * 'firstName' => 'Carl',
46
+ * 'lastName' => 'Jones',
47
+ * 'company' => 'Braintree',
48
+ * 'streetAddress' => '123 E Main St',
49
+ * 'extendedAddress' => 'Suite 403',
50
+ * 'locality' => 'Chicago',
51
+ * 'region' => 'IL',
52
+ * 'postalCode' => '60622',
53
+ * 'countryName' => 'United States of America'
54
+ * ),
55
+ * 'shipping' => array(
56
+ * 'firstName' => 'Andrew',
57
+ * 'lastName' => 'Mason',
58
+ * 'company' => 'Braintree',
59
+ * 'streetAddress' => '456 W Main St',
60
+ * 'extendedAddress' => 'Apt 2F',
61
+ * 'locality' => 'Bartlett',
62
+ * 'region' => 'IL',
63
+ * 'postalCode' => '60103',
64
+ * 'countryName' => 'United States of America'
65
+ * ),
66
+ * 'customFields' => array(
67
+ * 'birthdate' => '11/13/1954'
68
+ * )
69
+ * )
70
+ * </code>
71
+ *
72
+ * <b>== Storing in the Vault ==</b>
73
+ *
74
+ * The customer and credit card information used for
75
+ * a transaction can be stored in the vault by setting
76
+ * <i>transaction[options][storeInVault]</i> to true.
77
+ * <code>
78
+ * $transaction = Braintree_Transaction::saleNoValidate(array(
79
+ * 'customer' => array(
80
+ * 'firstName' => 'Adam',
81
+ * 'lastName' => 'Williams'
82
+ * ),
83
+ * 'creditCard' => array(
84
+ * 'number' => '5105105105105100',
85
+ * 'expirationDate' => '05/2012'
86
+ * ),
87
+ * 'options' => array(
88
+ * 'storeInVault' => true
89
+ * )
90
+ * ));
91
+ *
92
+ * echo $transaction->customerDetails->id
93
+ * // '865534'
94
+ * echo $transaction->creditCardDetails->token
95
+ * // '6b6m'
96
+ * </code>
97
+ *
98
+ * To also store the billing address in the vault, pass the
99
+ * <b>addBillingAddressToPaymentMethod</b> option.
100
+ * <code>
101
+ * Braintree_Transaction.saleNoValidate(array(
102
+ * ...
103
+ * 'options' => array(
104
+ * 'storeInVault' => true
105
+ * 'addBillingAddressToPaymentMethod' => true
106
+ * )
107
+ * ));
108
+ * </code>
109
+ *
110
+ * <b>== Submitting for Settlement==</b>
111
+ *
112
+ * This can only be done when the transction's
113
+ * status is <b>authorized</b>. If <b>amount</b> is not specified,
114
+ * the full authorized amount will be settled. If you would like to settle
115
+ * less than the full authorized amount, pass the desired amount.
116
+ * You cannot settle more than the authorized amount.
117
+ *
118
+ * A transaction can be submitted for settlement when created by setting
119
+ * $transaction[options][submitForSettlement] to true.
120
+ *
121
+ * <code>
122
+ * $transaction = Braintree_Transaction::saleNoValidate(array(
123
+ * 'amount' => '100.00',
124
+ * 'creditCard' => array(
125
+ * 'number' => '5105105105105100',
126
+ * 'expirationDate' => '05/2012'
127
+ * ),
128
+ * 'options' => array(
129
+ * 'submitForSettlement' => true
130
+ * )
131
+ * ));
132
+ * </code>
133
+ *
134
+ * <b>== More information ==</b>
135
+ *
136
+ * For more detailed information on Transactions, see {@link http://www.braintreepayments.com/gateway/transaction-api http://www.braintreepaymentsolutions.com/gateway/transaction-api}
137
+ *
138
+ * @package Braintree
139
+ * @category Resources
140
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
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 object $billingDetails transaction billing address
150
+ * @property-read string $createdAt transaction created timestamp
151
+ * @property-read object $applePayCardDetails transaction Apple Pay card info
152
+ * @property-read object $creditCardDetails transaction credit card info
153
+ * @property-read object $coinbaseDetails transaction Coinbase account info
154
+ * @property-read object $paypalDetails transaction paypal account info
155
+ * @property-read object $customerDetails transaction customer info
156
+ * @property-read array $customFields custom fields passed with the request
157
+ * @property-read string $processorResponseCode gateway response code
158
+ * @property-read string $additionalProcessorResponse raw response from processor
159
+ * @property-read object $shippingDetails transaction shipping address
160
+ * @property-read string $status transaction status
161
+ * @property-read array $statusHistory array of StatusDetails objects
162
+ * @property-read string $type transaction type
163
+ * @property-read string $updatedAt transaction updated timestamp
164
+ * @property-read object $disbursementDetails populated when transaction is disbursed
165
+ * @property-read object $disputes populated when transaction is disputed
166
+ *
167
+ */
168
+
169
+ final class Braintree_Transaction extends Braintree
170
+ {
171
+ // Transaction Status
172
+ const AUTHORIZATION_EXPIRED = 'authorization_expired';
173
+ const AUTHORIZING = 'authorizing';
174
+ const AUTHORIZED = 'authorized';
175
+ const GATEWAY_REJECTED = 'gateway_rejected';
176
+ const FAILED = 'failed';
177
+ const PROCESSOR_DECLINED = 'processor_declined';
178
+ const SETTLED = 'settled';
179
+ const SETTLING = 'settling';
180
+ const SUBMITTED_FOR_SETTLEMENT = 'submitted_for_settlement';
181
+ const VOIDED = 'voided';
182
+ const UNRECOGNIZED = 'unrecognized';
183
+ const SETTLEMENT_DECLINED = 'settlement_declined';
184
+ const SETTLEMENT_PENDING = 'settlement_pending';
185
+
186
+ // Transaction Escrow Status
187
+ const ESCROW_HOLD_PENDING = 'hold_pending';
188
+ const ESCROW_HELD = 'held';
189
+ const ESCROW_RELEASE_PENDING = 'release_pending';
190
+ const ESCROW_RELEASED = 'released';
191
+ const ESCROW_REFUNDED = 'refunded';
192
+
193
+ // Transaction Types
194
+ const SALE = 'sale';
195
+ const CREDIT = 'credit';
196
+
197
+ // Transaction Created Using
198
+ const FULL_INFORMATION = 'full_information';
199
+ const TOKEN = 'token';
200
+
201
+ // Transaction Sources
202
+ const API = 'api';
203
+ const CONTROL_PANEL = 'control_panel';
204
+ const RECURRING = 'recurring';
205
+
206
+ // Gateway Rejection Reason
207
+ const AVS = 'avs';
208
+ const AVS_AND_CVV = 'avs_and_cvv';
209
+ const CVV = 'cvv';
210
+ const DUPLICATE = 'duplicate';
211
+ const FRAUD = 'fraud';
212
+ const THREE_D_SECURE = 'three_d_secure';
213
+
214
+ // Industry Types
215
+ const LODGING_INDUSTRY = 'lodging';
216
+ const TRAVEL_AND_CRUISE_INDUSTRY = 'travel_cruise';
217
+
218
+ /**
219
+ * sets instance properties from an array of values
220
+ *
221
+ * @ignore
222
+ * @access protected
223
+ * @param array $transactionAttribs array of transaction data
224
+ * @return none
225
+ */
226
+ protected function _initialize($transactionAttribs)
227
+ {
228
+ $this->_attributes = $transactionAttribs;
229
+
230
+ if (isset($transactionAttribs['applePay'])) {
231
+ $this->_set('applePayCardDetails',
232
+ new Braintree_Transaction_ApplePayCardDetails(
233
+ $transactionAttribs['applePay']
234
+ )
235
+ );
236
+ }
237
+
238
+ if (isset($transactionAttribs['creditCard'])) {
239
+ $this->_set('creditCardDetails',
240
+ new Braintree_Transaction_CreditCardDetails(
241
+ $transactionAttribs['creditCard']
242
+ )
243
+ );
244
+ }
245
+
246
+ if (isset($transactionAttribs['coinbaseAccount'])) {
247
+ $this->_set('coinbaseDetails',
248
+ new Braintree_Transaction_CoinbaseDetails(
249
+ $transactionAttribs['coinbaseAccount']
250
+ )
251
+ );
252
+ }
253
+
254
+ if (isset($transactionAttribs['paypal'])) {
255
+ $this->_set('paypalDetails',
256
+ new Braintree_Transaction_PayPalDetails(
257
+ $transactionAttribs['paypal']
258
+ )
259
+ );
260
+ }
261
+
262
+ if (isset($transactionAttribs['customer'])) {
263
+ $this->_set('customerDetails',
264
+ new Braintree_Transaction_CustomerDetails(
265
+ $transactionAttribs['customer']
266
+ )
267
+ );
268
+ }
269
+
270
+ if (isset($transactionAttribs['billing'])) {
271
+ $this->_set('billingDetails',
272
+ new Braintree_Transaction_AddressDetails(
273
+ $transactionAttribs['billing']
274
+ )
275
+ );
276
+ }
277
+
278
+ if (isset($transactionAttribs['shipping'])) {
279
+ $this->_set('shippingDetails',
280
+ new Braintree_Transaction_AddressDetails(
281
+ $transactionAttribs['shipping']
282
+ )
283
+ );
284
+ }
285
+
286
+ if (isset($transactionAttribs['subscription'])) {
287
+ $this->_set('subscriptionDetails',
288
+ new Braintree_Transaction_SubscriptionDetails(
289
+ $transactionAttribs['subscription']
290
+ )
291
+ );
292
+ }
293
+
294
+ if (isset($transactionAttribs['descriptor'])) {
295
+ $this->_set('descriptor',
296
+ new Braintree_Descriptor(
297
+ $transactionAttribs['descriptor']
298
+ )
299
+ );
300
+ }
301
+
302
+ if (isset($transactionAttribs['disbursementDetails'])) {
303
+ $this->_set('disbursementDetails',
304
+ new Braintree_DisbursementDetails($transactionAttribs['disbursementDetails'])
305
+ );
306
+ }
307
+
308
+ $disputes = array();
309
+ if (isset($transactionAttribs['disputes'])) {
310
+ foreach ($transactionAttribs['disputes'] AS $dispute) {
311
+ $disputes[] = Braintree_Dispute::factory($dispute);
312
+ }
313
+ }
314
+
315
+ $this->_set('disputes', $disputes);
316
+
317
+ $statusHistory = array();
318
+ if (isset($transactionAttribs['statusHistory'])) {
319
+ foreach ($transactionAttribs['statusHistory'] AS $history) {
320
+ $statusHistory[] = new Braintree_Transaction_StatusDetails($history);
321
+ }
322
+ }
323
+
324
+ $this->_set('statusHistory', $statusHistory);
325
+
326
+ $addOnArray = array();
327
+ if (isset($transactionAttribs['addOns'])) {
328
+ foreach ($transactionAttribs['addOns'] AS $addOn) {
329
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
330
+ }
331
+ }
332
+ $this->_set('addOns', $addOnArray);
333
+
334
+ $discountArray = array();
335
+ if (isset($transactionAttribs['discounts'])) {
336
+ foreach ($transactionAttribs['discounts'] AS $discount) {
337
+ $discountArray[] = Braintree_Discount::factory($discount);
338
+ }
339
+ }
340
+ $this->_set('discounts', $discountArray);
341
+
342
+ if(isset($transactionAttribs['riskData'])) {
343
+ $this->_set('riskData', Braintree_RiskData::factory($transactionAttribs['riskData']));
344
+ }
345
+ }
346
+
347
+ /**
348
+ * returns a string representation of the transaction
349
+ * @return string
350
+ */
351
+ public function __toString()
352
+ {
353
+ // array of attributes to print
354
+ $display = array(
355
+ 'id', 'type', 'amount', 'status',
356
+ 'createdAt', 'creditCardDetails', 'customerDetails'
357
+ );
358
+
359
+ $displayAttributes = array();
360
+ foreach ($display AS $attrib) {
361
+ $displayAttributes[$attrib] = $this->$attrib;
362
+ }
363
+ return __CLASS__ . '[' .
364
+ Braintree_Util::attributesToString($displayAttributes) .']';
365
+ }
366
+
367
+ public function isEqual($otherTx)
368
+ {
369
+ return $this->id === $otherTx->id;
370
+ }
371
+
372
+ public function vaultCreditCard()
373
+ {
374
+ $token = $this->creditCardDetails->token;
375
+ if (empty($token)) {
376
+ return null;
377
+ }
378
+ else {
379
+ return Braintree_CreditCard::find($token);
380
+ }
381
+ }
382
+
383
+ public function vaultCustomer()
384
+ {
385
+ $customerId = $this->customerDetails->id;
386
+ if (empty($customerId)) {
387
+ return null;
388
+ }
389
+ else {
390
+ return Braintree_Customer::find($customerId);
391
+ }
392
+ }
393
+
394
+ public function isDisbursed() {
395
+ return $this->disbursementDetails->isValid();
396
+ }
397
+
398
+ /**
399
+ * factory method: returns an instance of Braintree_Transaction
400
+ * to the requesting method, with populated properties
401
+ *
402
+ * @ignore
403
+ * @return object instance of Braintree_Transaction
404
+ */
405
+ public static function factory($attributes)
406
+ {
407
+ $instance = new self();
408
+ $instance->_initialize($attributes);
409
+ return $instance;
410
+ }
411
+
412
+
413
+ // static methods redirecting to gateway
414
+
415
+ public static function cloneTransaction($transactionId, $attribs)
416
+ {
417
+ return Braintree_Configuration::gateway()->transaction()->cloneTransaction($transactionId, $attribs);
418
+ }
419
+
420
+ public static function createFromTransparentRedirect($queryString)
421
+ {
422
+ return Braintree_Configuration::gateway()->transaction()->createFromTransparentRedirect($queryString);
423
+ }
424
+
425
+ public static function createTransactionUrl()
426
+ {
427
+ return Braintree_Configuration::gateway()->transaction()->createTransactionUrl();
428
+ }
429
+
430
+ public static function credit($attribs)
431
+ {
432
+ return Braintree_Configuration::gateway()->transaction()->credit($attribs);
433
+ }
434
+
435
+ public static function creditNoValidate($attribs)
436
+ {
437
+ return Braintree_Configuration::gateway()->transaction()->creditNoValidate($attribs);
438
+ }
439
+
440
+ public static function find($id)
441
+ {
442
+ return Braintree_Configuration::gateway()->transaction()->find($id);
443
+ }
444
+
445
+ public static function sale($attribs)
446
+ {
447
+ return Braintree_Configuration::gateway()->transaction()->sale($attribs);
448
+ }
449
+
450
+ public static function saleNoValidate($attribs)
451
+ {
452
+ return Braintree_Configuration::gateway()->transaction()->saleNoValidate($attribs);
453
+ }
454
+
455
+ public static function search($query)
456
+ {
457
+ return Braintree_Configuration::gateway()->transaction()->search($query);
458
+ }
459
+
460
+ public static function fetch($query, $ids)
461
+ {
462
+ return Braintree_Configuration::gateway()->transaction()->fetch($query, $ids);
463
+ }
464
+
465
+ public static function void($transactionId)
466
+ {
467
+ return Braintree_Configuration::gateway()->transaction()->void($transactionId);
468
+ }
469
+
470
+ public static function voidNoValidate($transactionId)
471
+ {
472
+ return Braintree_Configuration::gateway()->transaction()->voidNoValidate($transactionId);
473
+ }
474
+
475
+ public static function submitForSettlement($transactionId, $amount = null)
476
+ {
477
+ return Braintree_Configuration::gateway()->transaction()->submitForSettlement($transactionId, $amount);
478
+ }
479
+
480
+ public static function submitForSettlementNoValidate($transactionId, $amount = null)
481
+ {
482
+ return Braintree_Configuration::gateway()->transaction()->submitForSettlementNoValidate($transactionId, $amount);
483
+ }
484
+
485
+ public static function holdInEscrow($transactionId)
486
+ {
487
+ return Braintree_Configuration::gateway()->transaction()->holdInEscrow($transactionId);
488
+ }
489
+
490
+ public static function releaseFromEscrow($transactionId)
491
+ {
492
+ return Braintree_Configuration::gateway()->transaction()->releaseFromEscrow($transactionId);
493
+ }
494
+
495
+ public static function cancelRelease($transactionId)
496
+ {
497
+ return Braintree_Configuration::gateway()->transaction()->cancelRelease($transactionId);
498
+ }
499
+
500
+ public static function refund($transactionId, $amount = null)
501
+ {
502
+ return Braintree_Configuration::gateway()->transaction()->refund($transactionId, $amount);
503
+ }
504
+ }
lib/Braintree/Transaction/AddressDetails.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Creates an instance of AddressDetails as returned from a transaction
4
+ *
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Transaction
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ *
10
+ * @property-read string $firstName
11
+ * @property-read string $lastName
12
+ * @property-read string $company
13
+ * @property-read string $streetAddress
14
+ * @property-read string $extendedAddress
15
+ * @property-read string $locality
16
+ * @property-read string $region
17
+ * @property-read string $postalCode
18
+ * @property-read string $countryName
19
+ * @uses Braintree_Instance inherits methods
20
+ */
21
+ class Braintree_Transaction_AddressDetails extends Braintree_Instance
22
+ {
23
+ protected $_attributes = array();
24
+ }
lib/Braintree/Transaction/ApplePayCardDetails.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Apple Pay card details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * creates an instance of ApplePayCardDetails
12
+ *
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Transaction
16
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
17
+ *
18
+ * @property-read string $cardType
19
+ * @property-read string $paymentInstrumentName
20
+ * @property-read string $expirationMonth
21
+ * @property-read string $expirationYear
22
+ * @property-read string $cardholderName
23
+ * @uses Braintree_Instance inherits methods
24
+ */
25
+ class Braintree_Transaction_ApplePayCardDetails extends Braintree_Instance
26
+ {
27
+ protected $_attributes = array();
28
+
29
+ /**
30
+ * @ignore
31
+ */
32
+ public function __construct($attributes)
33
+ {
34
+ parent::__construct($attributes);
35
+ }
36
+ }
lib/Braintree/Transaction/CoinbaseDetails.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Coinbase details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * creates an instance of Coinbase
12
+ *
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Transaction
16
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
17
+ *
18
+ * @property-read string $token
19
+ * @property-read string $userId
20
+ * @property-read string $userName
21
+ * @property-read string $userEmail
22
+ * @property-read string $imageUrl
23
+ * @uses Braintree_Instance inherits methods
24
+ */
25
+ class Braintree_Transaction_CoinbaseDetails extends Braintree_Instance
26
+ {
27
+ protected $_attributes = array();
28
+
29
+ /**
30
+ * @ignore
31
+ */
32
+ public function __construct($attributes)
33
+ {
34
+ parent::__construct($attributes);
35
+ }
36
+ }
lib/Braintree/Transaction/CreditCardDetails.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * CreditCard details from a transaction
4
+ * creates an instance of CreditCardDetails
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Transaction
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ *
10
+ * @property-read string $bin
11
+ * @property-read string $cardType
12
+ * @property-read string $expirationDate
13
+ * @property-read string $expirationMonth
14
+ * @property-read string $expirationYear
15
+ * @property-read string $issuerLocation
16
+ * @property-read string $last4
17
+ * @property-read string $maskedNumber
18
+ * @property-read string $token
19
+ * @uses Braintree_Instance inherits methods
20
+ */
21
+ class Braintree_Transaction_CreditCardDetails extends Braintree_Instance
22
+ {
23
+ protected $_attributes = array();
24
+
25
+ /**
26
+ * @ignore
27
+ */
28
+ public function __construct($attributes)
29
+ {
30
+ parent::__construct($attributes);
31
+ $this->_attributes['expirationDate'] = $this->expirationMonth . '/' . $this->expirationYear;
32
+ $this->_attributes['maskedNumber'] = $this->bin . '******' . $this->last4;
33
+
34
+ }
35
+ }
lib/Braintree/Transaction/CustomerDetails.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Customer details from a transaction
4
+ * Creates an instance of customer details as returned from a transaction
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Transaction
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ *
10
+ * @property-read string $company
11
+ * @property-read string $email
12
+ * @property-read string $fax
13
+ * @property-read string $firstName
14
+ * @property-read string $id
15
+ * @property-read string $lastName
16
+ * @property-read string $phone
17
+ * @property-read string $website
18
+ * @uses Braintree_Instance inherits methods
19
+ */
20
+ class Braintree_Transaction_CustomerDetails extends Braintree_Instance
21
+ {
22
+ }
lib/Braintree/Transaction/PayPalDetails.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PayPal details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * creates an instance of PayPalDetails
12
+ *
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Transaction
16
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
17
+ *
18
+ * @property-read string $payerEmail
19
+ * @property-read string $paymentId
20
+ * @property-read string $authorizationId
21
+ * @property-read string $token
22
+ * @property-read string $imageUrl
23
+ * @uses Braintree_Instance inherits methods
24
+ */
25
+ class Braintree_Transaction_PayPalDetails extends Braintree_Instance
26
+ {
27
+ protected $_attributes = array();
28
+
29
+ /**
30
+ * @ignore
31
+ */
32
+ public function __construct($attributes)
33
+ {
34
+ parent::__construct($attributes);
35
+ }
36
+ }
lib/Braintree/Transaction/StatusDetails.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Status details from a transaction
4
+ * Creates an instance of StatusDetails, as part of a transaction response
5
+ *
6
+ * @package Braintree
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ *
9
+ * @property-read string $amount
10
+ * @property-read string $status
11
+ * @property-read string $timestamp
12
+ * @property-read string $transactionSource
13
+ * @property-read string $user
14
+ * @uses Braintree_Instance inherits methods
15
+ */
16
+ class Braintree_Transaction_StatusDetails extends Braintree_Instance
17
+ {
18
+ }
lib/Braintree/Transaction/SubscriptionDetails.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Customer details from a transaction
4
+ * Creates an instance of customer details as returned from a transaction
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Transaction
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ *
10
+ * @property-read string $billing_period_start_date
11
+ * @property-read string $billing_period_end_date
12
+ */
13
+ class Braintree_Transaction_SubscriptionDetails extends Braintree_Instance
14
+ {
15
+ }
lib/Braintree/TransactionGateway.php ADDED
@@ -0,0 +1,444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree TransactionGateway processor
4
+ * Creates and manages transactions
5
+ *
6
+ *
7
+ * <b>== More information ==</b>
8
+ *
9
+ * For more detailed information on Transactions, see {@link http://www.braintreepayments.com/gateway/transaction-api http://www.braintreepaymentsolutions.com/gateway/transaction-api}
10
+ *
11
+ * @package Braintree
12
+ * @category Resources
13
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
14
+ */
15
+
16
+ final class Braintree_TransactionGateway
17
+ {
18
+ private $_gateway;
19
+ private $_config;
20
+ private $_http;
21
+
22
+ public function __construct($gateway)
23
+ {
24
+ $this->_gateway = $gateway;
25
+ $this->_config = $gateway->config;
26
+ $this->_http = new Braintree_Http($gateway->config);
27
+ }
28
+
29
+ public function cloneTransaction($transactionId, $attribs)
30
+ {
31
+ Braintree_Util::verifyKeys(self::cloneSignature(), $attribs);
32
+ return $this->_doCreate('/transactions/' . $transactionId . '/clone', array('transactionClone' => $attribs));
33
+ }
34
+
35
+ /**
36
+ * @ignore
37
+ * @access private
38
+ * @param array $attribs
39
+ * @return object
40
+ */
41
+ private function create($attribs)
42
+ {
43
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
44
+ return $this->_doCreate('/transactions', array('transaction' => $attribs));
45
+ }
46
+
47
+ /**
48
+ *
49
+ * @ignore
50
+ * @access private
51
+ * @param array $attribs
52
+ * @return object
53
+ * @throws Braintree_Exception_ValidationError
54
+ */
55
+ private function createNoValidate($attribs)
56
+ {
57
+ $result = $this->create($attribs);
58
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
59
+ }
60
+ /**
61
+ *
62
+ * @access public
63
+ * @param array $attribs
64
+ * @return object
65
+ */
66
+ public function createFromTransparentRedirect($queryString)
67
+ {
68
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
69
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
70
+ $queryString
71
+ );
72
+ return $this->_doCreate(
73
+ '/transactions/all/confirm_transparent_redirect_request',
74
+ array('id' => $params['id'])
75
+ );
76
+ }
77
+ /**
78
+ *
79
+ * @access public
80
+ * @param none
81
+ * @return string
82
+ */
83
+ public function createTransactionUrl()
84
+ {
85
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
86
+ return $this->_config->baseUrl() . $this->_config->merchantPath() .
87
+ '/transactions/all/create_via_transparent_redirect_request';
88
+ }
89
+
90
+ public static function cloneSignature()
91
+ {
92
+ return array('amount', 'channel', array('options' => array('submitForSettlement')));
93
+ }
94
+
95
+ /**
96
+ * creates a full array signature of a valid gateway request
97
+ * @return array gateway request signature format
98
+ */
99
+ public static function createSignature()
100
+ {
101
+ return array(
102
+ 'amount',
103
+ 'billingAddressId',
104
+ 'channel',
105
+ 'customerId',
106
+ 'deviceData',
107
+ 'deviceSessionId',
108
+ 'fraudMerchantId',
109
+ 'merchantAccountId',
110
+ 'orderId',
111
+ 'paymentMethodNonce',
112
+ 'paymentMethodToken',
113
+ 'purchaseOrderNumber',
114
+ 'recurring',
115
+ 'serviceFeeAmount',
116
+ 'shippingAddressId',
117
+ 'taxAmount',
118
+ 'taxExempt',
119
+ 'threeDSecureToken',
120
+ 'type',
121
+ 'venmoSdkPaymentMethodCode',
122
+ array('creditCard' =>
123
+ array('token', 'cardholderName', 'cvv', 'expirationDate', 'expirationMonth', 'expirationYear', 'number'),
124
+ ),
125
+ array('customer' =>
126
+ array(
127
+ 'id', 'company', 'email', 'fax', 'firstName',
128
+ 'lastName', 'phone', 'website'),
129
+ ),
130
+ array('billing' =>
131
+ array(
132
+ 'firstName', 'lastName', 'company', 'countryName',
133
+ 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
134
+ 'extendedAddress', 'locality', 'postalCode', 'region',
135
+ 'streetAddress'),
136
+ ),
137
+ array('shipping' =>
138
+ array(
139
+ 'firstName', 'lastName', 'company', 'countryName',
140
+ 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
141
+ 'extendedAddress', 'locality', 'postalCode', 'region',
142
+ 'streetAddress'),
143
+ ),
144
+ array('options' =>
145
+ array(
146
+ 'holdInEscrow',
147
+ 'storeInVault',
148
+ 'storeInVaultOnSuccess',
149
+ 'submitForSettlement',
150
+ 'addBillingAddressToPaymentMethod',
151
+ 'venmoSdkSession',
152
+ 'storeShippingAddressInVault',
153
+ 'payeeEmail',
154
+ array('three_d_secure' =>
155
+ array('required')
156
+ ),
157
+ array('paypal' =>
158
+ array(
159
+ 'payeeEmail',
160
+ 'customField'
161
+ )
162
+ )
163
+ ),
164
+ ),
165
+ array('customFields' => array('_anyKey_')
166
+ ),
167
+ array('descriptor' => array('name', 'phone', 'url')),
168
+ array('paypalAccount' => array('payeeEmail')),
169
+ array('industry' =>
170
+ array('industryType',
171
+ array('data' =>
172
+ array(
173
+ 'folioNumber',
174
+ 'checkInDate',
175
+ 'checkOutDate',
176
+ 'travelPackage',
177
+ 'departureDate',
178
+ 'lodgingCheckInDate',
179
+ 'lodgingCheckOutDate',
180
+ 'lodgingName',
181
+ 'roomRate'
182
+ )
183
+ )
184
+ )
185
+ )
186
+ );
187
+ }
188
+
189
+ /**
190
+ *
191
+ * @access public
192
+ * @param array $attribs
193
+ * @return object
194
+ */
195
+ public function credit($attribs)
196
+ {
197
+ return $this->create(array_merge($attribs, array('type' => Braintree_Transaction::CREDIT)));
198
+ }
199
+
200
+ /**
201
+ *
202
+ * @access public
203
+ * @param array $attribs
204
+ * @return object
205
+ * @throws Braintree_Exception_ValidationError
206
+ */
207
+ public function creditNoValidate($attribs)
208
+ {
209
+ $result = $this->credit($attribs);
210
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
211
+ }
212
+
213
+
214
+ /**
215
+ * @access public
216
+ *
217
+ */
218
+ public function find($id)
219
+ {
220
+ $this->_validateId($id);
221
+ try {
222
+ $path = $this->_config->merchantPath() . '/transactions/' . $id;
223
+ $response = $this->_http->get($path);
224
+ return Braintree_Transaction::factory($response['transaction']);
225
+ } catch (Braintree_Exception_NotFound $e) {
226
+ throw new Braintree_Exception_NotFound(
227
+ 'transaction with id ' . $id . ' not found'
228
+ );
229
+ }
230
+
231
+ }
232
+ /**
233
+ * new sale
234
+ * @param array $attribs
235
+ * @return array
236
+ */
237
+ public function sale($attribs)
238
+ {
239
+ return $this->create(array_merge(array('type' => Braintree_Transaction::SALE), $attribs));
240
+ }
241
+
242
+ /**
243
+ * roughly equivalent to the ruby bang method
244
+ * @access public
245
+ * @param array $attribs
246
+ * @return array
247
+ * @throws Braintree_Exception_ValidationsFailed
248
+ */
249
+ public function saleNoValidate($attribs)
250
+ {
251
+ $result = $this->sale($attribs);
252
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
253
+ }
254
+
255
+ /**
256
+ * Returns a ResourceCollection of transactions matching the search query.
257
+ *
258
+ * If <b>query</b> is a string, the search will be a basic search.
259
+ * If <b>query</b> is a hash, the search will be an advanced search.
260
+ * For more detailed information and examples, see {@link http://www.braintreepayments.com/gateway/transaction-api#searching http://www.braintreepaymentsolutions.com/gateway/transaction-api}
261
+ *
262
+ * @param mixed $query search query
263
+ * @param array $options options such as page number
264
+ * @return object Braintree_ResourceCollection
265
+ * @throws InvalidArgumentException
266
+ */
267
+ public function search($query)
268
+ {
269
+ $criteria = array();
270
+ foreach ($query as $term) {
271
+ $criteria[$term->name] = $term->toparam();
272
+ }
273
+
274
+ $path = $this->_config->merchantPath() . '/transactions/advanced_search_ids';
275
+ $response = $this->_http->post($path, array('search' => $criteria));
276
+ if (array_key_exists('searchResults', $response)) {
277
+ $pager = array(
278
+ 'object' => $this,
279
+ 'method' => 'fetch',
280
+ 'methodArgs' => array($query)
281
+ );
282
+
283
+ return new Braintree_ResourceCollection($response, $pager);
284
+ } else {
285
+ throw new Braintree_Exception_DownForMaintenance();
286
+ }
287
+ }
288
+
289
+ public function fetch($query, $ids)
290
+ {
291
+ $criteria = array();
292
+ foreach ($query as $term) {
293
+ $criteria[$term->name] = $term->toparam();
294
+ }
295
+ $criteria["ids"] = Braintree_TransactionSearch::ids()->in($ids)->toparam();
296
+ $path = $this->_config->merchantPath() . '/transactions/advanced_search';
297
+ $response = $this->_http->post($path, array('search' => $criteria));
298
+
299
+ return Braintree_Util::extractattributeasarray(
300
+ $response['creditCardTransactions'],
301
+ 'transaction'
302
+ );
303
+ }
304
+
305
+ /**
306
+ * void a transaction by id
307
+ *
308
+ * @param string $id transaction id
309
+ * @return object Braintree_Result_Successful|Braintree_Result_Error
310
+ */
311
+ public function void($transactionId)
312
+ {
313
+ $this->_validateId($transactionId);
314
+
315
+ $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/void';
316
+ $response = $this->_http->put($path);
317
+ return $this->_verifyGatewayResponse($response);
318
+ }
319
+ /**
320
+ *
321
+ */
322
+ public function voidNoValidate($transactionId)
323
+ {
324
+ $result = $this->void($transactionId);
325
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
326
+ }
327
+
328
+ public function submitForSettlement($transactionId, $amount = null)
329
+ {
330
+ $this->_validateId($transactionId);
331
+
332
+ $path = $this->_config->merchantPath() . '/transactions/'. $transactionId . '/submit_for_settlement';
333
+ $response = $this->_http->put($path, array('transaction' => array('amount' => $amount)));
334
+ return $this->_verifyGatewayResponse($response);
335
+ }
336
+
337
+ public function submitForSettlementNoValidate($transactionId, $amount = null)
338
+ {
339
+ $result = $this->submitForSettlement($transactionId, $amount);
340
+ return Braintree_Util::returnObjectOrThrowException(__CLASS__, $result);
341
+ }
342
+
343
+ public function holdInEscrow($transactionId)
344
+ {
345
+ $this->_validateId($transactionId);
346
+
347
+ $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/hold_in_escrow';
348
+ $response = $this->_http->put($path, array());
349
+ return $this->_verifyGatewayResponse($response);
350
+ }
351
+
352
+ public function releaseFromEscrow($transactionId)
353
+ {
354
+ $this->_validateId($transactionId);
355
+
356
+ $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/release_from_escrow';
357
+ $response = $this->_http->put($path, array());
358
+ return $this->_verifyGatewayResponse($response);
359
+ }
360
+
361
+ public function cancelRelease($transactionId)
362
+ {
363
+ $this->_validateId($transactionId);
364
+
365
+ $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/cancel_release';
366
+ $response = $this->_http->put($path, array());
367
+ return $this->_verifyGatewayResponse($response);
368
+ }
369
+
370
+ public function refund($transactionId, $amount = null)
371
+ {
372
+ self::_validateId($transactionId);
373
+
374
+ $params = array('transaction' => array('amount' => $amount));
375
+ $path = $this->_config->merchantPath() . '/transactions/' . $transactionId . '/refund';
376
+ $response = $this->_http->post($path, $params);
377
+ return $this->_verifyGatewayResponse($response);
378
+ }
379
+
380
+ /**
381
+ * sends the create request to the gateway
382
+ *
383
+ * @ignore
384
+ * @param var $subPath
385
+ * @param array $params
386
+ * @return mixed
387
+ */
388
+ public function _doCreate($subPath, $params)
389
+ {
390
+ $fullPath = $this->_config->merchantPath() . $subPath;
391
+ $response = $this->_http->post($fullPath, $params);
392
+
393
+ return $this->_verifyGatewayResponse($response);
394
+ }
395
+
396
+ /**
397
+ * verifies that a valid transaction id is being used
398
+ * @ignore
399
+ * @param string transaction id
400
+ * @throws InvalidArgumentException
401
+ */
402
+ private function _validateId($id = null) {
403
+ if (empty($id)) {
404
+ throw new InvalidArgumentException(
405
+ 'expected transaction id to be set'
406
+ );
407
+ }
408
+ if (!preg_match('/^[0-9a-z]+$/', $id)) {
409
+ throw new InvalidArgumentException(
410
+ $id . ' is an invalid transaction id.'
411
+ );
412
+ }
413
+ }
414
+
415
+
416
+ /**
417
+ * generic method for validating incoming gateway responses
418
+ *
419
+ * creates a new Braintree_Transaction object and encapsulates
420
+ * it inside a Braintree_Result_Successful object, or
421
+ * encapsulates a Braintree_Errors object inside a Result_Error
422
+ * alternatively, throws an Unexpected exception if the response is invalid.
423
+ *
424
+ * @ignore
425
+ * @param array $response gateway response values
426
+ * @return object Result_Successful or Result_Error
427
+ * @throws Braintree_Exception_Unexpected
428
+ */
429
+ private function _verifyGatewayResponse($response)
430
+ {
431
+ if (isset($response['transaction'])) {
432
+ // return a populated instance of Braintree_Transaction
433
+ return new Braintree_Result_Successful(
434
+ Braintree_Transaction::factory($response['transaction'])
435
+ );
436
+ } else if (isset($response['apiErrorResponse'])) {
437
+ return new Braintree_Result_Error($response['apiErrorResponse']);
438
+ } else {
439
+ throw new Braintree_Exception_Unexpected(
440
+ "Expected transaction or apiErrorResponse"
441
+ );
442
+ }
443
+ }
444
+ }
lib/Braintree/TransactionSearch.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_TransactionSearch
3
+ {
4
+ static function billingCompany() { return new Braintree_TextNode('billing_company'); }
5
+ static function billingCountryName() { return new Braintree_TextNode('billing_country_name'); }
6
+ static function billingExtendedAddress() { return new Braintree_TextNode('billing_extended_address'); }
7
+ static function billingFirstName() { return new Braintree_TextNode('billing_first_name'); }
8
+ static function billingLastName() { return new Braintree_TextNode('billing_last_name'); }
9
+ static function billingLocality() { return new Braintree_TextNode('billing_locality'); }
10
+ static function billingPostalCode() { return new Braintree_TextNode('billing_postal_code'); }
11
+ static function billingRegion() { return new Braintree_TextNode('billing_region'); }
12
+ static function billingStreetAddress() { return new Braintree_TextNode('billing_street_address'); }
13
+ static function creditCardCardholderName() { return new Braintree_TextNode('credit_card_cardholderName'); }
14
+ static function customerCompany() { return new Braintree_TextNode('customer_company'); }
15
+ static function customerEmail() { return new Braintree_TextNode('customer_email'); }
16
+ static function customerFax() { return new Braintree_TextNode('customer_fax'); }
17
+ static function customerFirstName() { return new Braintree_TextNode('customer_first_name'); }
18
+ static function customerId() { return new Braintree_TextNode('customer_id'); }
19
+ static function customerLastName() { return new Braintree_TextNode('customer_last_name'); }
20
+ static function customerPhone() { return new Braintree_TextNode('customer_phone'); }
21
+ static function customerWebsite() { return new Braintree_TextNode('customer_website'); }
22
+ static function id() { return new Braintree_TextNode('id'); }
23
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
24
+ static function orderId() { return new Braintree_TextNode('order_id'); }
25
+ static function paymentMethodToken() { return new Braintree_TextNode('payment_method_token'); }
26
+ static function processorAuthorizationCode() { return new Braintree_TextNode('processor_authorization_code'); }
27
+ static function settlementBatchId() { return new Braintree_TextNode('settlement_batch_id'); }
28
+ static function shippingCompany() { return new Braintree_TextNode('shipping_company'); }
29
+ static function shippingCountryName() { return new Braintree_TextNode('shipping_country_name'); }
30
+ static function shippingExtendedAddress() { return new Braintree_TextNode('shipping_extended_address'); }
31
+ static function shippingFirstName() { return new Braintree_TextNode('shipping_first_name'); }
32
+ static function shippingLastName() { return new Braintree_TextNode('shipping_last_name'); }
33
+ static function shippingLocality() { return new Braintree_TextNode('shipping_locality'); }
34
+ static function shippingPostalCode() { return new Braintree_TextNode('shipping_postal_code'); }
35
+ static function shippingRegion() { return new Braintree_TextNode('shipping_region'); }
36
+ static function shippingStreetAddress() { return new Braintree_TextNode('shipping_street_address'); }
37
+ static function paypalPaymentId() { return new Braintree_TextNode('paypal_payment_id'); }
38
+ static function paypalAuthorizationId() { return new Braintree_TextNode('paypal_authorization_id'); }
39
+ static function paypalPayerEmail() { return new Braintree_TextNode('paypal_payer_email'); }
40
+
41
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
42
+
43
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
44
+
45
+ static function refund() { return new Braintree_KeyValueNode("refund"); }
46
+
47
+ static function amount() { return new Braintree_RangeNode("amount"); }
48
+ static function authorizedAt() { return new Braintree_RangeNode("authorizedAt"); }
49
+ static function authorizationExpiredAt() { return new Braintree_RangeNode("authorizationExpiredAt"); }
50
+ static function createdAt() { return new Braintree_RangeNode("createdAt"); }
51
+ static function failedAt() { return new Braintree_RangeNode("failedAt"); }
52
+ static function gatewayRejectedAt() { return new Braintree_RangeNode("gatewayRejectedAt"); }
53
+ static function processorDeclinedAt() { return new Braintree_RangeNode("processorDeclinedAt"); }
54
+ static function settledAt() { return new Braintree_RangeNode("settledAt"); }
55
+ static function submittedForSettlementAt() { return new Braintree_RangeNode("submittedForSettlementAt"); }
56
+ static function voidedAt() { return new Braintree_RangeNode("voidedAt"); }
57
+ static function disbursementDate() { return new Braintree_RangeNode("disbursementDate"); }
58
+ static function disputeDate() { return new Braintree_RangeNode("disputeDate"); }
59
+
60
+ static function merchantAccountId() { return new Braintree_MultipleValueNode("merchant_account_id"); }
61
+
62
+ static function createdUsing()
63
+ {
64
+ return new Braintree_MultipleValueNode("created_using", array(
65
+ Braintree_Transaction::FULL_INFORMATION,
66
+ Braintree_Transaction::TOKEN
67
+ ));
68
+ }
69
+
70
+ static function creditCardCardType()
71
+ {
72
+ return new Braintree_MultipleValueNode("credit_card_card_type", array(
73
+ Braintree_CreditCard::AMEX,
74
+ Braintree_CreditCard::CARTE_BLANCHE,
75
+ Braintree_CreditCard::CHINA_UNION_PAY,
76
+ Braintree_CreditCard::DINERS_CLUB_INTERNATIONAL,
77
+ Braintree_CreditCard::DISCOVER,
78
+ Braintree_CreditCard::JCB,
79
+ Braintree_CreditCard::LASER,
80
+ Braintree_CreditCard::MAESTRO,
81
+ Braintree_CreditCard::MASTER_CARD,
82
+ Braintree_CreditCard::SOLO,
83
+ Braintree_CreditCard::SWITCH_TYPE,
84
+ Braintree_CreditCard::VISA,
85
+ Braintree_CreditCard::UNKNOWN
86
+ ));
87
+ }
88
+
89
+ static function creditCardCustomerLocation()
90
+ {
91
+ return new Braintree_MultipleValueNode("credit_card_customer_location", array(
92
+ Braintree_CreditCard::INTERNATIONAL,
93
+ Braintree_CreditCard::US
94
+ ));
95
+ }
96
+
97
+ static function source()
98
+ {
99
+ return new Braintree_MultipleValueNode("source", array(
100
+ Braintree_Transaction::API,
101
+ Braintree_Transaction::CONTROL_PANEL,
102
+ Braintree_Transaction::RECURRING,
103
+ ));
104
+ }
105
+
106
+ static function status()
107
+ {
108
+ return new Braintree_MultipleValueNode("status", array(
109
+ Braintree_Transaction::AUTHORIZATION_EXPIRED,
110
+ Braintree_Transaction::AUTHORIZING,
111
+ Braintree_Transaction::AUTHORIZED,
112
+ Braintree_Transaction::GATEWAY_REJECTED,
113
+ Braintree_Transaction::FAILED,
114
+ Braintree_Transaction::PROCESSOR_DECLINED,
115
+ Braintree_Transaction::SETTLED,
116
+ Braintree_Transaction::SETTLING,
117
+ Braintree_Transaction::SUBMITTED_FOR_SETTLEMENT,
118
+ Braintree_Transaction::VOIDED,
119
+ Braintree_Transaction::SETTLEMENT_DECLINED,
120
+ Braintree_Transaction::SETTLEMENT_PENDING
121
+ ));
122
+ }
123
+
124
+ static function type()
125
+ {
126
+ return new Braintree_MultipleValueNode("type", array(
127
+ Braintree_Transaction::SALE,
128
+ Braintree_Transaction::CREDIT
129
+ ));
130
+ }
131
+ }
lib/Braintree/TransparentRedirect.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Braintree Transparent Redirect module
6
+ * Static class providing methods to build Transparent Redirect urls
7
+ *
8
+ * The TransparentRedirect module provides methods to build the tr_data param
9
+ * that must be submitted when using the transparent redirect API.
10
+ * For more information
11
+ * about transparent redirect, see (TODO).
12
+ *
13
+ * You must provide a redirectUrl to which the gateway will redirect the
14
+ * user the action is complete.
15
+ *
16
+ * <code>
17
+ * $trData = Braintree_TransparentRedirect::createCustomerData(array(
18
+ * 'redirectUrl => 'http://example.com/redirect_back_to_merchant_site',
19
+ * ));
20
+ * </code>
21
+ *
22
+ * In addition to the redirectUrl, any data that needs to be protected
23
+ * from user tampering should be included in the trData.
24
+ * For example, to prevent the user from tampering with the transaction
25
+ * amount, include the amount in the trData.
26
+ *
27
+ * <code>
28
+ * $trData = Braintree_TransparentRedirect::transactionData(array(
29
+ * 'redirectUrl' => 'http://example.com/complete_transaction',
30
+ * 'transaction' => array('amount' => '100.00'),
31
+ * ));
32
+ *
33
+ * </code>
34
+ *
35
+ * @package Braintree
36
+ * @category Resources
37
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
38
+ */
39
+ class Braintree_TransparentRedirect
40
+ {
41
+ // Request Kinds
42
+ const CREATE_TRANSACTION = 'create_transaction';
43
+ const CREATE_PAYMENT_METHOD = 'create_payment_method';
44
+ const UPDATE_PAYMENT_METHOD = 'update_payment_method';
45
+ const CREATE_CUSTOMER = 'create_customer';
46
+ const UPDATE_CUSTOMER = 'update_customer';
47
+
48
+ /**
49
+ * @ignore
50
+ * don't permit an explicit call of the constructor!
51
+ * (like $t = new Braintree_TransparentRedirect())
52
+ */
53
+ protected function __construct()
54
+ {
55
+
56
+ }
57
+
58
+
59
+ // static methods redirecting to gateway
60
+
61
+ public static function confirm($queryString)
62
+ {
63
+ return Braintree_Configuration::gateway()->transparentRedirect()->confirm($queryString);
64
+ }
65
+
66
+ public static function createCreditCardData($params)
67
+ {
68
+ return Braintree_Configuration::gateway()->transparentRedirect()->createCreditCardData($params);
69
+ }
70
+
71
+ public static function createCustomerData($params)
72
+ {
73
+ return Braintree_Configuration::gateway()->transparentRedirect()->createCustomerData($params);
74
+ }
75
+
76
+ public static function url()
77
+ {
78
+ return Braintree_Configuration::gateway()->transparentRedirect()->url();
79
+ }
80
+
81
+ public static function transactionData($params)
82
+ {
83
+ return Braintree_Configuration::gateway()->transparentRedirect()->transactionData($params);
84
+ }
85
+
86
+ public static function updateCreditCardData($params)
87
+ {
88
+ return Braintree_Configuration::gateway()->transparentRedirect()->updateCreditCardData($params);
89
+ }
90
+
91
+ public static function updateCustomerData($params)
92
+ {
93
+ return Braintree_Configuration::gateway()->transparentRedirect()->updateCustomerData($params);
94
+ }
95
+
96
+ public static function parseAndValidateQueryString($queryString)
97
+ {
98
+ return Braintree_Configuration::gateway()->transparentRedirect()->parseAndValidateQueryString($queryString);
99
+ }
100
+ }
lib/Braintree/TransparentRedirectGateway.php ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Transparent Redirect Gateway module
4
+ * Static class providing methods to build Transparent Redirect urls
5
+ *
6
+ * @package Braintree
7
+ * @category Resources
8
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
9
+ */
10
+ class Braintree_TransparentRedirectGateway
11
+ {
12
+ private $_gateway;
13
+ private $_config;
14
+
15
+ public function __construct($gateway)
16
+ {
17
+ $this->_gateway = $gateway;
18
+ $this->_config = $gateway->config;
19
+ }
20
+
21
+ /**
22
+ *
23
+ * @ignore
24
+ */
25
+ private static $_transparentRedirectKeys = 'redirectUrl';
26
+ private static $_createCustomerSignature;
27
+ private static $_updateCustomerSignature;
28
+ private static $_transactionSignature;
29
+ private static $_createCreditCardSignature;
30
+ private static $_updateCreditCardSignature;
31
+
32
+ /**
33
+ * create signatures for different call types
34
+ * @ignore
35
+ */
36
+ public static function init()
37
+ {
38
+
39
+ self::$_createCustomerSignature = array(
40
+ self::$_transparentRedirectKeys,
41
+ array('customer' => Braintree_CustomerGateway::createSignature()),
42
+ );
43
+ self::$_updateCustomerSignature = array(
44
+ self::$_transparentRedirectKeys,
45
+ 'customerId',
46
+ array('customer' => Braintree_CustomerGateway::updateSignature()),
47
+ );
48
+ self::$_transactionSignature = array(
49
+ self::$_transparentRedirectKeys,
50
+ array('transaction' => Braintree_TransactionGateway::createSignature()),
51
+ );
52
+ self::$_createCreditCardSignature = array(
53
+ self::$_transparentRedirectKeys,
54
+ array('creditCard' => Braintree_CreditCardGateway::createSignature()),
55
+ );
56
+ self::$_updateCreditCardSignature = array(
57
+ self::$_transparentRedirectKeys,
58
+ 'paymentMethodToken',
59
+ array('creditCard' => Braintree_CreditCardGateway::updateSignature()),
60
+ );
61
+ }
62
+
63
+ public function confirm($queryString)
64
+ {
65
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
66
+ $queryString
67
+ );
68
+ $confirmationKlasses = array(
69
+ Braintree_TransparentRedirect::CREATE_TRANSACTION => 'Braintree_TransactionGateway',
70
+ Braintree_TransparentRedirect::CREATE_CUSTOMER => 'Braintree_CustomerGateway',
71
+ Braintree_TransparentRedirect::UPDATE_CUSTOMER => 'Braintree_CustomerGateway',
72
+ Braintree_TransparentRedirect::CREATE_PAYMENT_METHOD => 'Braintree_CreditCardGateway',
73
+ Braintree_TransparentRedirect::UPDATE_PAYMENT_METHOD => 'Braintree_CreditCardGateway'
74
+ );
75
+ $confirmationGateway = new $confirmationKlasses[$params["kind"]]($this->_gateway);
76
+ return $confirmationGateway->_doCreate('/transparent_redirect_requests/' . $params['id'] . '/confirm', array());
77
+ }
78
+
79
+ /**
80
+ * returns the trData string for creating a credit card,
81
+ * @param array $params
82
+ * @return string
83
+ */
84
+ public function createCreditCardData($params)
85
+ {
86
+ Braintree_Util::verifyKeys(
87
+ self::$_createCreditCardSignature,
88
+ $params
89
+ );
90
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_PAYMENT_METHOD;
91
+ return $this->_data($params);
92
+ }
93
+
94
+ /**
95
+ * returns the trData string for creating a customer.
96
+ * @param array $params
97
+ * @return string
98
+ */
99
+ public function createCustomerData($params)
100
+ {
101
+ Braintree_Util::verifyKeys(
102
+ self::$_createCustomerSignature,
103
+ $params
104
+ );
105
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_CUSTOMER;
106
+ return $this->_data($params);
107
+
108
+ }
109
+
110
+ public function url()
111
+ {
112
+ return $this->_config->baseUrl() . $this->_config->merchantPath() . "/transparent_redirect_requests";
113
+ }
114
+
115
+ /**
116
+ * returns the trData string for creating a transaction
117
+ * @param array $params
118
+ * @return string
119
+ */
120
+ public function transactionData($params)
121
+ {
122
+ Braintree_Util::verifyKeys(
123
+ self::$_transactionSignature,
124
+ $params
125
+ );
126
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_TRANSACTION;
127
+ $transactionType = isset($params['transaction']['type']) ?
128
+ $params['transaction']['type'] :
129
+ null;
130
+ if ($transactionType != Braintree_Transaction::SALE && $transactionType != Braintree_Transaction::CREDIT) {
131
+ throw new InvalidArgumentException(
132
+ 'expected transaction[type] of sale or credit, was: ' .
133
+ $transactionType
134
+ );
135
+ }
136
+
137
+ return $this->_data($params);
138
+ }
139
+
140
+ /**
141
+ * Returns the trData string for updating a credit card.
142
+ *
143
+ * The paymentMethodToken of the credit card to update is required.
144
+ *
145
+ * <code>
146
+ * $trData = Braintree_TransparentRedirect::updateCreditCardData(array(
147
+ * 'redirectUrl' => 'http://example.com/redirect_here',
148
+ * 'paymentMethodToken' => 'token123',
149
+ * ));
150
+ * </code>
151
+ *
152
+ * @param array $params
153
+ * @return string
154
+ */
155
+ public function updateCreditCardData($params)
156
+ {
157
+ Braintree_Util::verifyKeys(
158
+ self::$_updateCreditCardSignature,
159
+ $params
160
+ );
161
+ if (!isset($params['paymentMethodToken'])) {
162
+ throw new InvalidArgumentException(
163
+ 'expected params to contain paymentMethodToken.'
164
+ );
165
+ }
166
+ $params["kind"] = Braintree_TransparentRedirect::UPDATE_PAYMENT_METHOD;
167
+ return $this->_data($params);
168
+ }
169
+
170
+ /**
171
+ * Returns the trData string for updating a customer.
172
+ *
173
+ * The customerId of the customer to update is required.
174
+ *
175
+ * <code>
176
+ * $trData = Braintree_TransparentRedirect::updateCustomerData(array(
177
+ * 'redirectUrl' => 'http://example.com/redirect_here',
178
+ * 'customerId' => 'customer123',
179
+ * ));
180
+ * </code>
181
+ *
182
+ * @param array $params
183
+ * @return string
184
+ */
185
+ public function updateCustomerData($params)
186
+ {
187
+ Braintree_Util::verifyKeys(
188
+ self::$_updateCustomerSignature,
189
+ $params
190
+ );
191
+ if (!isset($params['customerId'])) {
192
+ throw new InvalidArgumentException(
193
+ 'expected params to contain customerId of customer to update'
194
+ );
195
+ }
196
+ $params["kind"] = Braintree_TransparentRedirect::UPDATE_CUSTOMER;
197
+ return $this->_data($params);
198
+ }
199
+
200
+ public function parseAndValidateQueryString($queryString)
201
+ {
202
+ // parse the params into an array
203
+ parse_str($queryString, $params);
204
+ // remove the hash
205
+ $queryStringWithoutHash = null;
206
+ if(preg_match('/^(.*)&hash=[a-f0-9]+$/', $queryString, $match)) {
207
+ $queryStringWithoutHash = $match[1];
208
+ }
209
+
210
+ if($params['http_status'] != '200') {
211
+ $message = null;
212
+ if(array_key_exists('bt_message', $params)) {
213
+ $message = $params['bt_message'];
214
+ }
215
+ Braintree_Util::throwStatusCodeException($params['http_status'], $message);
216
+ }
217
+
218
+ // recreate the hash and compare it
219
+ if($this->_hash($queryStringWithoutHash) == $params['hash']) {
220
+ return $params;
221
+ } else {
222
+ throw new Braintree_Exception_ForgedQueryString();
223
+ }
224
+ }
225
+
226
+
227
+ /**
228
+ *
229
+ * @ignore
230
+ */
231
+ private function _data($params)
232
+ {
233
+ if (!isset($params['redirectUrl'])) {
234
+ throw new InvalidArgumentException(
235
+ 'expected params to contain redirectUrl'
236
+ );
237
+ }
238
+ $params = $this->_underscoreKeys($params);
239
+ $now = new DateTime('now', new DateTimeZone('UTC'));
240
+ $trDataParams = array_merge($params,
241
+ array(
242
+ 'api_version' => Braintree_Configuration::API_VERSION,
243
+ 'public_key' => $this->_config->publicKey(),
244
+ 'time' => $now->format('YmdHis'),
245
+ )
246
+ );
247
+ ksort($trDataParams);
248
+ $urlEncodedData = http_build_query($trDataParams, null, "&");
249
+ $signatureService = new Braintree_SignatureService(
250
+ $this->_config->privateKey(),
251
+ "Braintree_Digest::hexDigestSha1"
252
+ );
253
+ return $signatureService->sign($urlEncodedData);
254
+ }
255
+
256
+ private function _underscoreKeys($array)
257
+ {
258
+ foreach($array as $key=>$value)
259
+ {
260
+ $newKey = Braintree_Util::camelCaseToDelimiter($key, '_');
261
+ unset($array[$key]);
262
+ if (is_array($value))
263
+ {
264
+ $array[$newKey] = $this->_underscoreKeys($value);
265
+ }
266
+ else
267
+ {
268
+ $array[$newKey] = $value;
269
+ }
270
+ }
271
+ return $array;
272
+ }
273
+
274
+ /**
275
+ * @ignore
276
+ */
277
+ private function _hash($string)
278
+ {
279
+ return Braintree_Digest::hexDigestSha1($this->_config->privateKey(), $string);
280
+ }
281
+ }
282
+ Braintree_TransparentRedirectGateway::init();
lib/Braintree/UnknownPaymentMethod.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree UnknownPaymentMethod module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+
10
+ /**
11
+ * Manages Braintree UnknownPaymentMethod
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ *
16
+ * @package Braintree
17
+ * @category Resources
18
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
19
+ *
20
+ * @property-read string $token
21
+ * @property-read string $imageUrl
22
+ */
23
+ class Braintree_UnknownPaymentMethod extends Braintree
24
+ {
25
+
26
+
27
+ /**
28
+ * factory method: returns an instance of Braintree_UnknownPaymentMethod
29
+ * to the requesting method, with populated properties
30
+ *
31
+ * @ignore
32
+ * @return object instance of Braintree_UnknownPaymentMethod
33
+ */
34
+ public static function factory($attributes)
35
+ {
36
+ $instance = new self();
37
+ $values = array_values($attributes);
38
+ $instance->_initialize(array_shift($values));
39
+ return $instance;
40
+ }
41
+
42
+ /* instance methods */
43
+
44
+ /**
45
+ * returns false if default is null or false
46
+ *
47
+ * @return boolean
48
+ */
49
+ public function isDefault()
50
+ {
51
+ return $this->default;
52
+ }
53
+
54
+ /**
55
+ * sets instance properties from an array of values
56
+ *
57
+ * @access protected
58
+ * @param array $unknownPaymentMethodAttribs array of unknownPaymentMethod data
59
+ * @return none
60
+ */
61
+ protected function _initialize($unknownPaymentMethodAttribs)
62
+ {
63
+ // set the attributes
64
+ $this->imageUrl = 'https://assets.braintreegateway.com/payment_method_logo/unknown.png';
65
+ $this->_attributes = $unknownPaymentMethodAttribs;
66
+ }
67
+
68
+ }
lib/Braintree/Util.php ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Utility methods
4
+ * PHP version 5
5
+ *
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ */
8
+
9
+ class Braintree_Util
10
+ {
11
+ /**
12
+ * extracts an attribute and returns an array of objects
13
+ *
14
+ * extracts the requested element from an array, and converts the contents
15
+ * of its child arrays to objects of type Braintree_$attributeName, or returns
16
+ * an array with a single element containing the value of that array element
17
+ *
18
+ * @param array $attribArray attributes from a search response
19
+ * @param string $attributeName indicates which element of the passed array to extract
20
+ *
21
+ * @return array array of Braintree_$attributeName objects, or a single element array
22
+ */
23
+ public static function extractAttributeAsArray(& $attribArray, $attributeName)
24
+ {
25
+ if(!isset($attribArray[$attributeName])):
26
+ return array();
27
+ endif;
28
+
29
+ // get what should be an array from the passed array
30
+ $data = $attribArray[$attributeName];
31
+ // set up the class that will be used to convert each array element
32
+ $classFactory = self::buildClassName($attributeName) . '::factory';
33
+ if(is_array($data)):
34
+ // create an object from the data in each element
35
+ $objectArray = array_map($classFactory, $data);
36
+ else:
37
+ return array($data);
38
+ endif;
39
+
40
+ unset($attribArray[$attributeName]);
41
+ return $objectArray;
42
+ }
43
+ /**
44
+ * throws an exception based on the type of error
45
+ * @param string $statusCode HTTP status code to throw exception from
46
+ * @throws Braintree_Exception multiple types depending on the error
47
+ *
48
+ */
49
+ public static function throwStatusCodeException($statusCode, $message=null)
50
+ {
51
+ switch($statusCode) {
52
+ case 401:
53
+ throw new Braintree_Exception_Authentication();
54
+ break;
55
+ case 403:
56
+ throw new Braintree_Exception_Authorization($message);
57
+ break;
58
+ case 404:
59
+ throw new Braintree_Exception_NotFound();
60
+ break;
61
+ case 426:
62
+ throw new Braintree_Exception_UpgradeRequired();
63
+ break;
64
+ case 500:
65
+ throw new Braintree_Exception_ServerError();
66
+ break;
67
+ case 503:
68
+ throw new Braintree_Exception_DownForMaintenance();
69
+ break;
70
+ default:
71
+ throw new Braintree_Exception_Unexpected('Unexpected HTTP_RESPONSE #'.$statusCode);
72
+ break;
73
+ }
74
+ }
75
+
76
+ /**
77
+ *
78
+ * @param string $className
79
+ * @param object $resultObj
80
+ * @return object returns the passed object if successful
81
+ * @throws Braintree_Exception_ValidationsFailed
82
+ */
83
+ public static function returnObjectOrThrowException($className, $resultObj)
84
+ {
85
+ $resultObjName = Braintree_Util::cleanClassName($className);
86
+ if ($resultObj->success) {
87
+ return $resultObj->$resultObjName;
88
+ } else {
89
+ throw new Braintree_Exception_ValidationsFailed();
90
+ }
91
+ }
92
+
93
+ /**
94
+ * removes the Braintree_ header from a classname
95
+ *
96
+ * @param string $name Braintree_ClassName
97
+ * @return camelCased classname minus Braintree_ header
98
+ */
99
+ public static function cleanClassName($name)
100
+ {
101
+ $classNamesToResponseKeys = array(
102
+ 'CreditCard' => 'creditCard',
103
+ 'CreditCardGateway' => 'creditCard',
104
+ 'Customer' => 'customer',
105
+ 'CustomerGateway' => 'customer',
106
+ 'Subscription' => 'subscription',
107
+ 'SubscriptionGateway' => 'subscription',
108
+ 'Transaction' => 'transaction',
109
+ 'TransactionGateway' => 'transaction',
110
+ 'CreditCardVerification' => 'verification',
111
+ 'CreditCardVerificationGateway' => 'verification',
112
+ 'AddOn' => 'addOn',
113
+ 'AddOnGateway' => 'addOn',
114
+ 'Discount' => 'discount',
115
+ 'DiscountGateway' => 'discount',
116
+ 'Plan' => 'plan',
117
+ 'PlanGateway' => 'plan',
118
+ 'Address' => 'address',
119
+ 'AddressGateway' => 'address',
120
+ 'SettlementBatchSummary' => 'settlementBatchSummary',
121
+ 'SettlementBatchSummaryGateway' => 'settlementBatchSummary',
122
+ 'MerchantAccount' => 'merchantAccount',
123
+ 'MerchantAccountGateway' => 'merchantAccount',
124
+ 'PayPalAccount' => 'paypalAccount',
125
+ 'PayPalAccountGateway' => 'paypalAccount'
126
+ );
127
+
128
+ $name = str_replace('Braintree_', '', $name);
129
+ return $classNamesToResponseKeys[$name];
130
+ }
131
+
132
+ /**
133
+ *
134
+ * @param string $name className
135
+ * @return string Braintree_ClassName
136
+ */
137
+ public static function buildClassName($name)
138
+ {
139
+ $responseKeysToClassNames = array(
140
+ 'creditCard' => 'CreditCard',
141
+ 'customer' => 'Customer',
142
+ 'subscription' => 'Subscription',
143
+ 'transaction' => 'Transaction',
144
+ 'verification' => 'CreditCardVerification',
145
+ 'addOn' => 'AddOn',
146
+ 'discount' => 'Discount',
147
+ 'plan' => 'Plan',
148
+ 'address' => 'Address',
149
+ 'settlementBatchSummary' => 'SettlementBatchSummary',
150
+ 'merchantAccount' => 'MerchantAccount'
151
+ );
152
+
153
+ return 'Braintree_' . $responseKeysToClassNames[$name];
154
+ }
155
+
156
+ /**
157
+ * convert alpha-beta-gamma to alphaBetaGamma
158
+ *
159
+ * @access public
160
+ * @param string $string
161
+ * @return string modified string
162
+ */
163
+ public static function delimiterToCamelCase($string, $delimiter = '[\-\_]')
164
+ {
165
+ // php doesn't garbage collect functions created by create_function()
166
+ // so use a static variable to avoid adding a new function to memory
167
+ // every time this function is called.
168
+ static $callback = null;
169
+ if ($callback === null) {
170
+ $callback = create_function('$matches', 'return strtoupper($matches[1]);');
171
+ }
172
+
173
+ return preg_replace_callback('/' . $delimiter . '(\w)/', $callback, $string);
174
+ }
175
+
176
+ /**
177
+ * convert alpha-beta-gamma to alpha_beta_gamma
178
+ *
179
+ * @access public
180
+ * @param string $string
181
+ * @return string modified string
182
+ */
183
+ public static function delimiterToUnderscore($string)
184
+ {
185
+ return preg_replace('/-/', '_', $string);
186
+ }
187
+
188
+
189
+ /**
190
+ * find capitals and convert to delimiter + lowercase
191
+ *
192
+ * @access public
193
+ * @param var $string
194
+ * @return var modified string
195
+ */
196
+ public static function camelCaseToDelimiter($string, $delimiter = '-')
197
+ {
198
+ // php doesn't garbage collect functions created by create_function()
199
+ // so use a static variable to avoid adding a new function to memory
200
+ // every time this function is called.
201
+ static $callbacks = array();
202
+ if (!isset($callbacks[$delimiter])) {
203
+ $callbacks[$delimiter] = create_function('$matches', "return '$delimiter' . strtolower(\$matches[1]);");
204
+ }
205
+
206
+ return preg_replace_callback('/([A-Z])/', $callbacks[$delimiter], $string);
207
+ }
208
+
209
+ /**
210
+ *
211
+ * @param array $array associative array to implode
212
+ * @param string $separator (optional, defaults to =)
213
+ * @param string $glue (optional, defaults to ', ')
214
+ */
215
+ public static function implodeAssociativeArray($array, $separator = '=', $glue = ', ')
216
+ {
217
+ // build a new array with joined keys and values
218
+ $tmpArray = null;
219
+ foreach ($array AS $key => $value) {
220
+ $tmpArray[] = $key . $separator . $value;
221
+
222
+ }
223
+ // implode and return the new array
224
+ return (is_array($tmpArray)) ? implode($glue, $tmpArray) : false;
225
+ }
226
+
227
+ public static function attributesToString($attributes) {
228
+ $printableAttribs = array();
229
+ foreach ($attributes AS $key => $value) {
230
+ if (is_array($value)) {
231
+ $pAttrib = Braintree_Util::attributesToString($value);
232
+ } else if ($value instanceof DateTime) {
233
+ $pAttrib = $value->format(DateTime::RFC850);
234
+ } else {
235
+ $pAttrib = $value;
236
+ }
237
+ $printableAttribs[$key] = sprintf('%s', $pAttrib);
238
+ }
239
+ return Braintree_Util::implodeAssociativeArray($printableAttribs);
240
+ }
241
+
242
+ /**
243
+ * verify user request structure
244
+ *
245
+ * compares the expected signature of a gateway request
246
+ * against the actual structure sent by the user
247
+ *
248
+ * @param array $signature
249
+ * @param array $attributes
250
+ */
251
+ public static function verifyKeys($signature, $attributes)
252
+ {
253
+ $validKeys = self::_flattenArray($signature);
254
+ $userKeys = self::_flattenUserKeys($attributes);
255
+ $invalidKeys = array_diff($userKeys, $validKeys);
256
+ $invalidKeys = self::_removeWildcardKeys($validKeys, $invalidKeys);
257
+
258
+ if(!empty($invalidKeys)) {
259
+ asort($invalidKeys);
260
+ $sortedList = join(', ', $invalidKeys);
261
+ throw new InvalidArgumentException('invalid keys: '. $sortedList);
262
+ }
263
+ }
264
+ /**
265
+ * flattens a numerically indexed nested array to a single level
266
+ * @param array $keys
267
+ * @param string $namespace
268
+ * @return array
269
+ */
270
+ private static function _flattenArray($keys, $namespace = null)
271
+ {
272
+ $flattenedArray = array();
273
+ foreach($keys AS $key) {
274
+ if(is_array($key)) {
275
+ $theKeys = array_keys($key);
276
+ $theValues = array_values($key);
277
+ $scope = $theKeys[0];
278
+ $fullKey = empty($namespace) ? $scope : $namespace . '[' . $scope . ']';
279
+ $flattenedArray = array_merge($flattenedArray, self::_flattenArray($theValues[0], $fullKey));
280
+ } else {
281
+ $fullKey = empty($namespace) ? $key : $namespace . '[' . $key . ']';
282
+ $flattenedArray[] = $fullKey;
283
+ }
284
+ }
285
+ sort($flattenedArray);
286
+ return $flattenedArray;
287
+ }
288
+
289
+ private static function _flattenUserKeys($keys, $namespace = null)
290
+ {
291
+ $flattenedArray = array();
292
+
293
+ foreach($keys AS $key => $value) {
294
+ $fullKey = empty($namespace) ? $key : $namespace;
295
+ if (!is_numeric($key) && $namespace != null) {
296
+ $fullKey .= '[' . $key . ']';
297
+ }
298
+ if (is_numeric($key) && is_string($value)) {
299
+ $fullKey .= '[' . $value . ']';
300
+ }
301
+ if(is_array($value)) {
302
+ $more = self::_flattenUserKeys($value, $fullKey);
303
+ $flattenedArray = array_merge($flattenedArray, $more);
304
+ } else {
305
+ $flattenedArray[] = $fullKey;
306
+ }
307
+ }
308
+ sort($flattenedArray);
309
+ return $flattenedArray;
310
+ }
311
+
312
+ /**
313
+ * removes wildcard entries from the invalid keys array
314
+ * @param array $validKeys
315
+ * @param <array $invalidKeys
316
+ * @return array
317
+ */
318
+ private static function _removeWildcardKeys($validKeys, $invalidKeys)
319
+ {
320
+ foreach($validKeys AS $key) {
321
+ if (stristr($key, '[_anyKey_]')) {
322
+ $wildcardKey = str_replace('[_anyKey_]', '', $key);
323
+ foreach ($invalidKeys AS $index => $invalidKey) {
324
+ if (stristr($invalidKey, $wildcardKey)) {
325
+ unset($invalidKeys[$index]);
326
+ }
327
+ }
328
+ }
329
+ }
330
+ return $invalidKeys;
331
+ }
332
+ }
lib/Braintree/Version.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Library Version
4
+ * stores version information about the Braintree library
5
+ *
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ */
8
+ final class Braintree_Version
9
+ {
10
+ /**
11
+ * class constants
12
+ */
13
+ const MAJOR = 2;
14
+ const MINOR = 37;
15
+ const TINY = 0;
16
+
17
+ /**
18
+ * @ignore
19
+ * @access protected
20
+ */
21
+ protected function __construct()
22
+ {
23
+ }
24
+
25
+ /**
26
+ *
27
+ * @return string the current library version
28
+ */
29
+ public static function get()
30
+ {
31
+ return self::MAJOR.'.'.self::MINOR.'.'.self::TINY;
32
+ }
33
+ }
lib/Braintree/WebhookNotification.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_WebhookNotification extends Braintree
3
+ {
4
+ const SUBSCRIPTION_CANCELED = 'subscription_canceled';
5
+ const SUBSCRIPTION_CHARGED_SUCCESSFULLY = 'subscription_charged_successfully';
6
+ const SUBSCRIPTION_CHARGED_UNSUCCESSFULLY = 'subscription_charged_unsuccessfully';
7
+ const SUBSCRIPTION_EXPIRED = 'subscription_expired';
8
+ const SUBSCRIPTION_TRIAL_ENDED = 'subscription_trial_ended';
9
+ const SUBSCRIPTION_WENT_ACTIVE = 'subscription_went_active';
10
+ const SUBSCRIPTION_WENT_PAST_DUE = 'subscription_went_past_due';
11
+ const SUB_MERCHANT_ACCOUNT_APPROVED = 'sub_merchant_account_approved';
12
+ const SUB_MERCHANT_ACCOUNT_DECLINED = 'sub_merchant_account_declined';
13
+ const TRANSACTION_DISBURSED = 'transaction_disbursed';
14
+ const DISBURSEMENT_EXCEPTION = 'disbursement_exception';
15
+ const DISBURSEMENT = 'disbursement';
16
+ const DISPUTE_OPENED = 'dispute_opened';
17
+ const DISPUTE_LOST = 'dispute_lost';
18
+ const DISPUTE_WON = 'dispute_won';
19
+ const PARTNER_MERCHANT_CONNECTED = 'partner_merchant_connected';
20
+ const PARTNER_MERCHANT_DISCONNECTED = 'partner_merchant_disconnected';
21
+ const PARTNER_MERCHANT_DECLINED = 'partner_merchant_declined';
22
+
23
+ public static function parse($signature, $payload)
24
+ {
25
+ if (preg_match("/[^A-Za-z0-9+=\/\n]/", $payload) === 1) {
26
+ throw new Braintree_Exception_InvalidSignature("payload contains illegal characters");
27
+ }
28
+ self::_validateSignature($signature, $payload);
29
+
30
+ $xml = base64_decode($payload);
31
+ $attributes = Braintree_Xml::buildArrayFromXml($xml);
32
+ return self::factory($attributes['notification']);
33
+ }
34
+
35
+ public static function verify($challenge)
36
+ {
37
+ $publicKey = Braintree_Configuration::publicKey();
38
+ $digest = Braintree_Digest::hexDigestSha1(Braintree_Configuration::privateKey(), $challenge);
39
+ return "{$publicKey}|{$digest}";
40
+ }
41
+
42
+ public static function factory($attributes)
43
+ {
44
+ $instance = new self();
45
+ $instance->_initialize($attributes);
46
+ return $instance;
47
+ }
48
+
49
+ private static function _matchingSignature($signaturePairs)
50
+ {
51
+ foreach ($signaturePairs as $pair)
52
+ {
53
+ $components = preg_split("/\|/", $pair);
54
+ if ($components[0] == Braintree_Configuration::publicKey()) {
55
+ return $components[1];
56
+ }
57
+ }
58
+
59
+ return null;
60
+ }
61
+
62
+ private static function _payloadMatches($signature, $payload)
63
+ {
64
+ $payloadSignature = Braintree_Digest::hexDigestSha1(Braintree_Configuration::privateKey(), $payload);
65
+ return Braintree_Digest::secureCompare($signature, $payloadSignature);
66
+ }
67
+
68
+ private static function _validateSignature($signatureString, $payload)
69
+ {
70
+ $signaturePairs = preg_split("/&/", $signatureString);
71
+ $signature = self::_matchingSignature($signaturePairs);
72
+ if (!$signature) {
73
+ throw new Braintree_Exception_InvalidSignature("no matching public key");
74
+ }
75
+
76
+ if (!(self::_payloadMatches($signature, $payload) || self::_payloadMatches($signature, $payload . "\n"))) {
77
+ throw new Braintree_Exception_InvalidSignature("signature does not match payload - one has been modified");
78
+ }
79
+ }
80
+
81
+ protected function _initialize($attributes)
82
+ {
83
+ $this->_attributes = $attributes;
84
+
85
+ if (isset($attributes['subject']['apiErrorResponse'])) {
86
+ $wrapperNode = $attributes['subject']['apiErrorResponse'];
87
+ } else {
88
+ $wrapperNode = $attributes['subject'];
89
+ }
90
+
91
+ if (isset($wrapperNode['subscription'])) {
92
+ $this->_set('subscription', Braintree_Subscription::factory($attributes['subject']['subscription']));
93
+ }
94
+
95
+ if (isset($wrapperNode['merchantAccount'])) {
96
+ $this->_set('merchantAccount', Braintree_MerchantAccount::factory($wrapperNode['merchantAccount']));
97
+ }
98
+
99
+ if (isset($wrapperNode['transaction'])) {
100
+ $this->_set('transaction', Braintree_Transaction::factory($wrapperNode['transaction']));
101
+ }
102
+
103
+ if (isset($wrapperNode['disbursement'])) {
104
+ $this->_set('disbursement', Braintree_Disbursement::factory($wrapperNode['disbursement']));
105
+ }
106
+
107
+ if (isset($wrapperNode['partnerMerchant'])) {
108
+ $this->_set('partnerMerchant', Braintree_PartnerMerchant::factory($wrapperNode['partnerMerchant']));
109
+ }
110
+
111
+ if (isset($wrapperNode['dispute'])) {
112
+ $this->_set('dispute', Braintree_PartnerMerchant::factory($wrapperNode['dispute']));
113
+ }
114
+
115
+ if (isset($wrapperNode['errors'])) {
116
+ $this->_set('errors', new Braintree_Error_ValidationErrorCollection($wrapperNode['errors']));
117
+ $this->_set('message', $wrapperNode['message']);
118
+ }
119
+ }
120
+ }
lib/Braintree/WebhookTesting.php ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_WebhookTesting
3
+ {
4
+ public static function sampleNotification($kind, $id)
5
+ {
6
+ $payload = base64_encode(self::_sampleXml($kind, $id)) . "\n";
7
+ $signature = Braintree_Configuration::publicKey() . "|" . Braintree_Digest::hexDigestSha1(Braintree_Configuration::privateKey(), $payload);
8
+
9
+ return array(
10
+ 'bt_signature' => $signature,
11
+ 'bt_payload' => $payload
12
+ );
13
+ }
14
+
15
+ private static function _sampleXml($kind, $id)
16
+ {
17
+ switch ($kind) {
18
+ case Braintree_WebhookNotification::SUB_MERCHANT_ACCOUNT_APPROVED:
19
+ $subjectXml = self::_merchantAccountApprovedSampleXml($id);
20
+ break;
21
+ case Braintree_WebhookNotification::SUB_MERCHANT_ACCOUNT_DECLINED:
22
+ $subjectXml = self::_merchantAccountDeclinedSampleXml($id);
23
+ break;
24
+ case Braintree_WebhookNotification::TRANSACTION_DISBURSED:
25
+ $subjectXml = self::_transactionDisbursedSampleXml($id);
26
+ break;
27
+ case Braintree_WebhookNotification::DISBURSEMENT_EXCEPTION:
28
+ $subjectXml = self::_disbursementExceptionSampleXml($id);
29
+ break;
30
+ case Braintree_WebhookNotification::DISBURSEMENT:
31
+ $subjectXml = self::_disbursementSampleXml($id);
32
+ break;
33
+ case Braintree_WebhookNotification::PARTNER_MERCHANT_CONNECTED:
34
+ $subjectXml = self::_partnerMerchantConnectedSampleXml($id);
35
+ break;
36
+ case Braintree_WebhookNotification::PARTNER_MERCHANT_DISCONNECTED:
37
+ $subjectXml = self::_partnerMerchantDisconnectedSampleXml($id);
38
+ break;
39
+ case Braintree_WebhookNotification::PARTNER_MERCHANT_DECLINED:
40
+ $subjectXml = self::_partnerMerchantDeclinedSampleXml($id);
41
+ break;
42
+ case Braintree_WebhookNotification::DISPUTE_OPENED:
43
+ $subjectXml = self::_disputeOpenedSampleXml($id);
44
+ break;
45
+ case Braintree_WebhookNotification::DISPUTE_LOST:
46
+ $subjectXml = self::_disputeLostSampleXml($id);
47
+ break;
48
+ case Braintree_WebhookNotification::DISPUTE_WON:
49
+ $subjectXml = self::_disputeWonSampleXml($id);
50
+ break;
51
+ default:
52
+ $subjectXml = self::_subscriptionSampleXml($id);
53
+ break;
54
+ }
55
+ $timestamp = self::_timestamp();
56
+ return "
57
+ <notification>
58
+ <timestamp type=\"datetime\">{$timestamp}</timestamp>
59
+ <kind>{$kind}</kind>
60
+ <subject>{$subjectXml}</subject>
61
+ </notification>
62
+ ";
63
+ }
64
+
65
+ private static function _merchantAccountApprovedSampleXml($id)
66
+ {
67
+ return "
68
+ <merchant_account>
69
+ <id>{$id}</id>
70
+ <master_merchant_account>
71
+ <id>master_ma_for_{$id}</id>
72
+ <status>active</status>
73
+ </master_merchant_account>
74
+ <status>active</status>
75
+ </merchant_account>
76
+ ";
77
+ }
78
+
79
+ private static function _merchantAccountDeclinedSampleXml($id)
80
+ {
81
+ return "
82
+ <api-error-response>
83
+ <message>Credit score is too low</message>
84
+ <errors>
85
+ <errors type=\"array\"/>
86
+ <merchant-account>
87
+ <errors type=\"array\">
88
+ <error>
89
+ <code>82621</code>
90
+ <message>Credit score is too low</message>
91
+ <attribute type=\"symbol\">base</attribute>
92
+ </error>
93
+ </errors>
94
+ </merchant-account>
95
+ </errors>
96
+ <merchant-account>
97
+ <id>{$id}</id>
98
+ <status>suspended</status>
99
+ <master-merchant-account>
100
+ <id>master_ma_for_{$id}</id>
101
+ <status>suspended</status>
102
+ </master-merchant-account>
103
+ </merchant-account>
104
+ </api-error-response>
105
+ ";
106
+ }
107
+
108
+ private static function _transactionDisbursedSampleXml($id)
109
+ {
110
+ return "
111
+ <transaction>
112
+ <id>${id}</id>
113
+ <amount>100</amount>
114
+ <disbursement-details>
115
+ <disbursement-date type=\"date\">2013-07-09</disbursement-date>
116
+ </disbursement-details>
117
+ </transaction>
118
+ ";
119
+ }
120
+
121
+ private static function _disbursementExceptionSampleXml($id)
122
+ {
123
+ return "
124
+ <disbursement>
125
+ <id>${id}</id>
126
+ <transaction-ids type=\"array\">
127
+ <item>asdfg</item>
128
+ <item>qwert</item>
129
+ </transaction-ids>
130
+ <success type=\"boolean\">false</success>
131
+ <retry type=\"boolean\">false</retry>
132
+ <merchant-account>
133
+ <id>merchant_account_token</id>
134
+ <currency-iso-code>USD</currency-iso-code>
135
+ <sub-merchant-account type=\"boolean\">false</sub-merchant-account>
136
+ <status>active</status>
137
+ </merchant-account>
138
+ <amount>100.00</amount>
139
+ <disbursement-date type=\"date\">2014-02-10</disbursement-date>
140
+ <exception-message>bank_rejected</exception-message>
141
+ <follow-up-action>update_funding_information</follow-up-action>
142
+ </disbursement>
143
+ ";
144
+ }
145
+
146
+ private static function _disbursementSampleXml($id)
147
+ {
148
+ return "
149
+ <disbursement>
150
+ <id>${id}</id>
151
+ <transaction-ids type=\"array\">
152
+ <item>asdfg</item>
153
+ <item>qwert</item>
154
+ </transaction-ids>
155
+ <success type=\"boolean\">true</success>
156
+ <retry type=\"boolean\">false</retry>
157
+ <merchant-account>
158
+ <id>merchant_account_token</id>
159
+ <currency-iso-code>USD</currency-iso-code>
160
+ <sub-merchant-account type=\"boolean\">false</sub-merchant-account>
161
+ <status>active</status>
162
+ </merchant-account>
163
+ <amount>100.00</amount>
164
+ <disbursement-date type=\"date\">2014-02-10</disbursement-date>
165
+ <exception-message nil=\"true\"/>
166
+ <follow-up-action nil=\"true\"/>
167
+ </disbursement>
168
+ ";
169
+ }
170
+
171
+ private static function _disputeOpenedSampleXml($id)
172
+ {
173
+ return "
174
+ <dispute>
175
+ <amount>250.00</amount>
176
+ <currency-iso-code>USD</currency-iso-code>
177
+ <received-date type=\"date\">2014-03-01</received-date>
178
+ <reply-by-date type=\"date\">2014-03-21</reply-by-date>
179
+ <status>open</status>
180
+ <reason>fraud</reason>
181
+ <id>${id}</id>
182
+ <transaction>
183
+ <id>${id}</id>
184
+ <amount>250.00</amount>
185
+ </transaction>
186
+ </dispute>
187
+ ";
188
+ }
189
+
190
+ private static function _disputeLostSampleXml($id)
191
+ {
192
+ return "
193
+ <dispute>
194
+ <amount>250.00</amount>
195
+ <currency-iso-code>USD</currency-iso-code>
196
+ <received-date type=\"date\">2014-03-01</received-date>
197
+ <reply-by-date type=\"date\">2014-03-21</reply-by-date>
198
+ <status>lost</status>
199
+ <reason>fraud</reason>
200
+ <id>${id}</id>
201
+ <transaction>
202
+ <id>${id}</id>
203
+ <amount>250.00</amount>
204
+ </transaction>
205
+ </dispute>
206
+ ";
207
+ }
208
+
209
+ private static function _disputeWonSampleXml($id)
210
+ {
211
+ return "
212
+ <dispute>
213
+ <amount>250.00</amount>
214
+ <currency-iso-code>USD</currency-iso-code>
215
+ <received-date type=\"date\">2014-03-01</received-date>
216
+ <reply-by-date type=\"date\">2014-03-21</reply-by-date>
217
+ <status>won</status>
218
+ <reason>fraud</reason>
219
+ <id>${id}</id>
220
+ <transaction>
221
+ <id>${id}</id>
222
+ <amount>250.00</amount>
223
+ </transaction>
224
+ </dispute>
225
+ ";
226
+ }
227
+
228
+ private static function _subscriptionSampleXml($id)
229
+ {
230
+ return "
231
+ <subscription>
232
+ <id>{$id}</id>
233
+ <transactions type=\"array\">
234
+ </transactions>
235
+ <add_ons type=\"array\">
236
+ </add_ons>
237
+ <discounts type=\"array\">
238
+ </discounts>
239
+ </subscription>
240
+ ";
241
+ }
242
+
243
+ private static function _partnerMerchantConnectedSampleXml($id)
244
+ {
245
+ return "
246
+ <partner-merchant>
247
+ <merchant-public-id>public_id</merchant-public-id>
248
+ <public-key>public_key</public-key>
249
+ <private-key>private_key</private-key>
250
+ <partner-merchant-id>abc123</partner-merchant-id>
251
+ <client-side-encryption-key>cse_key</client-side-encryption-key>
252
+ </partner-merchant>
253
+ ";
254
+ }
255
+
256
+ private static function _partnerMerchantDisconnectedSampleXml($id)
257
+ {
258
+ return "
259
+ <partner-merchant>
260
+ <partner-merchant-id>abc123</partner-merchant-id>
261
+ </partner-merchant>
262
+ ";
263
+ }
264
+
265
+ private static function _partnerMerchantDeclinedSampleXml($id)
266
+ {
267
+ return "
268
+ <partner-merchant>
269
+ <partner-merchant-id>abc123</partner-merchant-id>
270
+ </partner-merchant>
271
+ ";
272
+ }
273
+
274
+ private static function _timestamp()
275
+ {
276
+ $originalZone = date_default_timezone_get();
277
+ date_default_timezone_set('UTC');
278
+ $timestamp = strftime('%Y-%m-%dT%TZ');
279
+ date_default_timezone_set($originalZone);
280
+
281
+ return $timestamp;
282
+ }
283
+ }
lib/Braintree/Xml.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Xml parser and generator
4
+ * PHP version 5
5
+ * superclass for Braintree XML parsing and generation
6
+ *
7
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
8
+ */
9
+ final class Braintree_Xml
10
+ {
11
+ /**
12
+ * @ignore
13
+ */
14
+ protected function __construct()
15
+ {
16
+
17
+ }
18
+
19
+ /**
20
+ *
21
+ * @param string $xml
22
+ * @return array
23
+ */
24
+ public static function buildArrayFromXml($xml)
25
+ {
26
+ return Braintree_Xml_Parser::arrayFromXml($xml);
27
+ }
28
+
29
+ /**
30
+ *
31
+ * @param array $array
32
+ * @return string
33
+ */
34
+ public static function buildXmlFromArray($array)
35
+ {
36
+ return Braintree_Xml_Generator::arrayToXml($array);
37
+ }
38
+ }
lib/Braintree/Xml/Generator.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP version 5
4
+ *
5
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
6
+ */
7
+
8
+ /**
9
+ * Generates XML output from arrays using PHP's
10
+ * built-in XMLWriter
11
+ *
12
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
13
+ */
14
+ class Braintree_Xml_Generator
15
+ {
16
+ /**
17
+ * arrays passed to this method should have a single root element
18
+ * with an array as its value
19
+ * @param array $aData the array of data
20
+ * @return var XML string
21
+ */
22
+ public static function arrayToXml($aData)
23
+ {
24
+ // set up the XMLWriter
25
+ $writer = new XMLWriter();
26
+ $writer->openMemory();
27
+
28
+ $writer->setIndent(true);
29
+ $writer->setIndentString(' ');
30
+ $writer->startDocument('1.0', 'UTF-8');
31
+
32
+ // get the root element name
33
+ $aKeys = array_keys($aData);
34
+ $rootElementName = $aKeys[0];
35
+ // open the root element
36
+ $writer->startElement(Braintree_Util::camelCaseToDelimiter($rootElementName));
37
+ // create the body
38
+ self::_createElementsFromArray($writer, $aData[$rootElementName], $rootElementName);
39
+
40
+ // close the root element and document
41
+ $writer->endElement();
42
+ $writer->endDocument();
43
+
44
+ // send the output as string
45
+ return $writer->outputMemory();
46
+ }
47
+
48
+ /**
49
+ * Construct XML elements with attributes from an associative array.
50
+ *
51
+ * @access protected
52
+ * @static
53
+ * @param object $writer XMLWriter object
54
+ * @param array $aData contains attributes and values
55
+ * @return none
56
+ */
57
+ private static function _createElementsFromArray(&$writer, $aData)
58
+ {
59
+ if (!is_array($aData)) {
60
+ if (is_bool($aData)) {
61
+ $writer->text($aData ? 'true' : 'false');
62
+ } else {
63
+ $writer->text($aData);
64
+ }
65
+ return;
66
+ }
67
+ foreach ($aData AS $index => $element) {
68
+ // convert the style back to gateway format
69
+ $elementName = Braintree_Util::camelCaseToDelimiter($index, '-');
70
+ // handle child elements
71
+ $writer->startElement($elementName);
72
+ if (is_array($element)) {
73
+ if (array_key_exists(0, $element) || empty($element)) {
74
+ $writer->writeAttribute('type', 'array');
75
+ foreach ($element AS $ignored => $itemInArray) {
76
+ $writer->startElement('item');
77
+ self::_createElementsFromArray($writer, $itemInArray);
78
+ $writer->endElement();
79
+ }
80
+ }
81
+ else {
82
+ self::_createElementsFromArray($writer, $element);
83
+ }
84
+ } else {
85
+ // generate attributes as needed
86
+ $attribute = self::_generateXmlAttribute($element);
87
+ if (is_array($attribute)) {
88
+ $writer->writeAttribute($attribute[0], $attribute[1]);
89
+ $element = $attribute[2];
90
+ }
91
+ $writer->text($element);
92
+ }
93
+ $writer->endElement();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * convert passed data into an array of attributeType, attributeName, and value
99
+ * dates sent as DateTime objects will be converted to strings
100
+ * @access protected
101
+ * @param mixed $value
102
+ * @return array attributes and element value
103
+ */
104
+ private static function _generateXmlAttribute($value)
105
+ {
106
+ if ($value instanceof DateTime) {
107
+ return array('type', 'datetime', self::_dateTimeToXmlTimestamp($value));
108
+ }
109
+ if (is_int($value)) {
110
+ return array('type', 'integer', $value);
111
+ }
112
+ if (is_bool($value)) {
113
+ return array('type', 'boolean', ($value ? 'true' : 'false'));
114
+ }
115
+ if ($value === NULL) {
116
+ return array('nil', 'true', $value);
117
+ }
118
+ }
119
+ /**
120
+ * converts datetime back to xml schema format
121
+ * @access protected
122
+ * @param object $dateTime
123
+ * @return var XML schema formatted timestamp
124
+ */
125
+ private static function _dateTimeToXmlTimestamp($dateTime)
126
+ {
127
+ $dateTime->setTimeZone(new DateTimeZone('UTC'));
128
+ return ($dateTime->format('Y-m-d\TH:i:s') . 'Z');
129
+ }
130
+
131
+ private static function _castDateTime($string)
132
+ {
133
+ try {
134
+ if (empty($string)) {
135
+ return false;
136
+ }
137
+ $dateTime = new DateTime($string);
138
+ return self::_dateTimeToXmlTimestamp($dateTime);
139
+ } catch (Exception $e) {
140
+ // not a datetime
141
+ return false;
142
+ }
143
+ }
144
+ }
lib/Braintree/Xml/Parser.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Braintree XML Parser
5
+ *
6
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
7
+ */
8
+ /**
9
+ * Parses incoming Xml into arrays using PHP's
10
+ * built-in SimpleXML, and its extension via
11
+ * Iterator, SimpleXMLIterator
12
+ *
13
+ * @copyright 2014 Braintree, a division of PayPal, Inc.
14
+ */
15
+ class Braintree_Xml_Parser
16
+ {
17
+
18
+ private static $_xmlRoot;
19
+ private static $_responseType;
20
+
21
+ /**
22
+ * sets up the SimpleXMLIterator and starts the parsing
23
+ * @access public
24
+ * @param string $xml
25
+ * @return array array mapped to the passed xml
26
+ */
27
+ public static function arrayFromXml($xml)
28
+ {
29
+ // SimpleXML provides the root information on construct
30
+ $iterator = new SimpleXMLIterator($xml);
31
+ $xmlRoot = Braintree_Util::delimiterToCamelCase($iterator->getName());
32
+ $type = $iterator->attributes()->type;
33
+
34
+ self::$_xmlRoot = $iterator->getName();
35
+ self::$_responseType = $type;
36
+
37
+ // return the mapped array with the root element as the header
38
+ return array($xmlRoot => self::_iteratorToArray($iterator));
39
+
40
+ }
41
+
42
+ /**
43
+ * processes SimpleXMLIterator objects recursively
44
+ *
45
+ * @access protected
46
+ * @param object $iterator
47
+ * @return array xml converted to array
48
+ */
49
+ private static function _iteratorToArray($iterator)
50
+ {
51
+ $xmlArray = array();
52
+ $value = null;
53
+
54
+ // rewind the iterator and check if the position is valid
55
+ // if not, return the string it contains
56
+ $iterator->rewind();
57
+ if (!$iterator->valid()) {
58
+ return self::_typecastXmlValue($iterator);
59
+ }
60
+ for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
61
+
62
+ $tmpArray = null;
63
+ $value = null;
64
+
65
+ // get the attribute type string for use in conditions below
66
+ $attributeType = $iterator->attributes()->type;
67
+
68
+ // extract the parent element via xpath query
69
+ $parentElement = $iterator->xpath($iterator->key() . '/..');
70
+ if ($parentElement[0] instanceof SimpleXMLIterator) {
71
+ $parentElement = $parentElement[0];
72
+ $parentKey = Braintree_Util::delimiterToCamelCase($parentElement->getName());
73
+ } else {
74
+ $parentElement = null;
75
+ }
76
+
77
+
78
+ if ($parentKey == "customFields") {
79
+ $key = Braintree_Util::delimiterToUnderscore($iterator->key());
80
+ } else {
81
+ $key = Braintree_Util::delimiterToCamelCase($iterator->key());
82
+ }
83
+
84
+ // process children recursively
85
+ if ($iterator->hasChildren()) {
86
+ // return the child elements
87
+ $value = self::_iteratorToArray($iterator->current());
88
+
89
+ // if the element is an array type,
90
+ // use numeric keys to allow multiple values
91
+ if ($attributeType != 'array') {
92
+ $tmpArray[$key] = $value;
93
+ }
94
+ } else {
95
+ // cast values according to attributes
96
+ $tmpArray[$key] = self::_typecastXmlValue($iterator->current());
97
+ }
98
+
99
+ // set the output string
100
+ $output = isset($value) ? $value : $tmpArray[$key];
101
+
102
+ // determine if there are multiple tags of this name at the same level
103
+ if (isset($parentElement) &&
104
+ ($parentElement->attributes()->type == 'collection') &&
105
+ $iterator->hasChildren()) {
106
+ $xmlArray[$key][] = $output;
107
+ continue;
108
+ }
109
+
110
+ // if the element was an array type, output to a numbered key
111
+ // otherwise, use the element name
112
+ if ($attributeType == 'array') {
113
+ $xmlArray[] = $output;
114
+ } else {
115
+ $xmlArray[$key] = $output;
116
+ }
117
+ }
118
+
119
+ return $xmlArray;
120
+ }
121
+
122
+ /**
123
+ * typecast xml value based on attributes
124
+ * @param object $valueObj SimpleXMLElement
125
+ * @return mixed value for placing into array
126
+ */
127
+ private static function _typecastXmlValue($valueObj)
128
+ {
129
+ // get the element attributes
130
+ $attribs = $valueObj->attributes();
131
+ // the element is null, so jump out here
132
+ if (isset($attribs->nil) && $attribs->nil) {
133
+ return null;
134
+ }
135
+ // switch on the type attribute
136
+ // switch works even if $attribs->type isn't set
137
+ switch ($attribs->type) {
138
+ case 'datetime':
139
+ return self::_timestampToUTC((string) $valueObj);
140
+ break;
141
+ case 'date':
142
+ return new DateTime((string)$valueObj);
143
+ break;
144
+ case 'integer':
145
+ return (int) $valueObj;
146
+ break;
147
+ case 'boolean':
148
+ $value = (string) $valueObj;
149
+ // look for a number inside the string
150
+ if(is_numeric($value)) {
151
+ return (bool) $value;
152
+ } else {
153
+ // look for the string "true", return false in all other cases
154
+ return ($value != "true") ? FALSE : TRUE;
155
+ }
156
+ break;
157
+ case 'array':
158
+ return array();
159
+ default:
160
+ return (string) $valueObj;
161
+ }
162
+
163
+ }
164
+
165
+ /**
166
+ * convert xml timestamps into DateTime
167
+ * @param string $timestamp
168
+ * @return string UTC formatted datetime string
169
+ */
170
+ private static function _timestampToUTC($timestamp)
171
+ {
172
+ $tz = new DateTimeZone('UTC');
173
+ // strangely DateTime requires an explicit set below
174
+ // to show the proper time zone
175
+ $dateTime = new DateTime($timestamp, $tz);
176
+ $dateTime->setTimezone($tz);
177
+ return $dateTime;
178
+ }
179
+ }
lib/ssl/api_braintreegateway_com.ca.crt ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
3
+ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
4
+ c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
5
+ MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
6
+ emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
7
+ DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
8
+ FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
9
+ UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
10
+ YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
11
+ MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
12
+ AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
13
+ pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
14
+ 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
15
+ AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
16
+ U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
17
+ F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
18
+ oJ2daZH9
19
+ -----END CERTIFICATE-----
20
+ -----BEGIN CERTIFICATE-----
21
+ MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
22
+ CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
23
+ cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
24
+ LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
25
+ aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
26
+ dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
27
+ VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
28
+ aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
29
+ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
30
+ IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
31
+ LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
32
+ N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
33
+ KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
34
+ kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
35
+ CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
36
+ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
37
+ imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
38
+ 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
39
+ DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
40
+ /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
41
+ F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
42
+ TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
43
+ -----END CERTIFICATE-----
44
+ -----BEGIN CERTIFICATE-----
45
+ MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
46
+ MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
47
+ ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
48
+ biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
49
+ U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
50
+ aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
51
+ A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
52
+ U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
53
+ SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
54
+ biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
55
+ IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
56
+ GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
57
+ fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
58
+ AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
59
+ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
60
+ aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
61
+ kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
62
+ 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
63
+ FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
64
+ -----END CERTIFICATE-----
65
+ -----BEGIN CERTIFICATE-----
66
+ MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
67
+ yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
68
+ ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
69
+ U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
70
+ ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
71
+ aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
72
+ MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
73
+ ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
74
+ biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
75
+ U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
76
+ aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
77
+ nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
78
+ t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
79
+ SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
80
+ BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
81
+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
82
+ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
83
+ BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
84
+ BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
85
+ aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
86
+ MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
87
+ p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
88
+ 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
89
+ WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
90
+ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
91
+ hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
92
+ -----END CERTIFICATE-----
93
+ -----BEGIN CERTIFICATE-----
94
+ MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
95
+ A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
96
+ cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
97
+ MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
98
+ BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
99
+ YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
100
+ ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
101
+ BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
102
+ I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
103
+ CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
104
+ 2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
105
+ 2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
106
+ -----END CERTIFICATE-----
107
+ -----BEGIN CERTIFICATE-----
108
+ MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
109
+ MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
110
+ FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
111
+ MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
112
+ cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
113
+ AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
114
+ Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
115
+ 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
116
+ wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
117
+ 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
118
+ 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
119
+ BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
120
+ /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
121
+ JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
122
+ NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
123
+ 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
124
+ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
125
+ D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
126
+ CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
127
+ 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
128
+ -----END CERTIFICATE-----
129
+ -----BEGIN CERTIFICATE-----
130
+ MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
131
+ EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
132
+ EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
133
+ ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
134
+ NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
135
+ EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
136
+ AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
137
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
138
+ E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
139
+ /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
140
+ DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
141
+ GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
142
+ tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
143
+ AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
144
+ FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
145
+ WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
146
+ 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
147
+ gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
148
+ 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
149
+ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
150
+ 4uJEvlz36hz1
151
+ -----END CERTIFICATE-----
152
+ -----BEGIN CERTIFICATE-----
153
+ MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
154
+ MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
155
+ c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
156
+ VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
157
+ c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
158
+ AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
159
+ WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
160
+ FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
161
+ XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
162
+ se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
163
+ KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
164
+ IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
165
+ y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
166
+ hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
167
+ QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
168
+ Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
169
+ HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
170
+ HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
171
+ KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
172
+ dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
173
+ L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
174
+ Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
175
+ ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
176
+ T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
177
+ GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
178
+ 1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
179
+ OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
180
+ 6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
181
+ QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
182
+ -----END CERTIFICATE-----
183
+ -----BEGIN CERTIFICATE-----
184
+ MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
185
+ MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
186
+ c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
187
+ BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
188
+ IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
189
+ VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
190
+ cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
191
+ QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
192
+ F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
193
+ c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
194
+ mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
195
+ VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
196
+ teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
197
+ f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
198
+ Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
199
+ nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
200
+ /wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
201
+ MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
202
+ 9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
203
+ aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
204
+ IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
205
+ ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
206
+ uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
207
+ Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
208
+ QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
209
+ koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
210
+ ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
211
+ DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
212
+ bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
213
+ -----END CERTIFICATE-----
214
+ -----BEGIN CERTIFICATE-----
215
+ MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
216
+ MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
217
+ IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
218
+ EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
219
+ R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
220
+ PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
221
+ Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
222
+ TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
223
+ 5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
224
+ S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
225
+ 2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
226
+ FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
227
+ EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
228
+ EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
229
+ /NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
230
+ A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
231
+ abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
232
+ I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
233
+ 4iIprn2DQKi6bA==
234
+ -----END CERTIFICATE-----
235
+ -----BEGIN CERTIFICATE-----
236
+ MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
237
+ MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
238
+ YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
239
+ EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
240
+ R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
241
+ 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
242
+ fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
243
+ iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
244
+ 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
245
+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
246
+ MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
247
+ ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
248
+ uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
249
+ Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
250
+ tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
251
+ PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
252
+ hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
253
+ 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
254
+ -----END CERTIFICATE-----
255
+ -----BEGIN CERTIFICATE-----
256
+ MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
257
+ MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
258
+ FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
259
+ MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
260
+ cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
261
+ AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
262
+ Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
263
+ 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
264
+ wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
265
+ 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
266
+ 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
267
+ BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
268
+ /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
269
+ JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
270
+ NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
271
+ 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
272
+ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
273
+ D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
274
+ CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
275
+ 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
276
+ -----END CERTIFICATE-----
277
+ -----BEGIN CERTIFICATE-----
278
+ MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
279
+ MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
280
+ IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
281
+ BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
282
+ MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
283
+ d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
284
+ YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
285
+ dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
286
+ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
287
+ papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
288
+ BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
289
+ DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
290
+ KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
291
+ XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
292
+ -----END CERTIFICATE-----
293
+ -----BEGIN CERTIFICATE-----
294
+ MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
295
+ qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
296
+ Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
297
+ MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
298
+ BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
299
+ NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
300
+ LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
301
+ A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
302
+ IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
303
+ SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
304
+ W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
305
+ 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
306
+ 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
307
+ Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
308
+ NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
309
+ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
310
+ r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
311
+ DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
312
+ YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
313
+ xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
314
+ /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
315
+ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
316
+ jVaMaA==
317
+ -----END CERTIFICATE-----
318
+ -----BEGIN CERTIFICATE-----
319
+ MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
320
+ MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
321
+ IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
322
+ BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
323
+ MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
324
+ d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
325
+ YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
326
+ dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
327
+ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
328
+ papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
329
+ BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
330
+ DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
331
+ KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
332
+ XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
333
+ -----END CERTIFICATE-----
334
+ -----BEGIN CERTIFICATE-----
335
+ MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
336
+ IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
337
+ BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
338
+ aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
339
+ 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
340
+ NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
341
+ azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
342
+ YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
343
+ Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
344
+ cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
345
+ dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
346
+ WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
347
+ v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
348
+ UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
349
+ IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
350
+ W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
351
+ -----END CERTIFICATE-----
lib/ssl/sandbox_braintreegateway_com.ca.crt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
2
+ -----BEGIN CERTIFICATE-----
3
+ MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
4
+ IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
5
+ BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
6
+ aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
7
+ 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
8
+ NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
9
+ azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
10
+ YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
11
+ Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
12
+ cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
13
+ dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
14
+ WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
15
+ v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
16
+ UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
17
+ IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
18
+ W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
19
+ -----END CERTIFICATE-----
20
+
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Gene_Braintree</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/mit-license.php">MIT License</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Connect your Magento store to Braintree to accept Credit Cards &amp;amp; PayPal using V.Zero SDK</summary>
10
+ <description>Connect your Magento store to Braintree to accept Credit Cards &amp;amp; PayPal using V.Zero SDK</description>
11
+ <notes>Connect your Magento store to Braintree to accept Credit Cards &amp;amp; PayPal using V.Zero SDK</notes>
12
+ <authors><author><name>Dave Macaulay</name><user>dave</user><email>magento@gene.co.uk</email></author></authors>
13
+ <date>2015-04-20</date>
14
+ <time>14:05:41</time>
15
+ <contents><target name="magecommunity"><dir name="Gene"><dir name="Braintree"><dir name="Block"><dir name="Adminhtml"><dir name="Report"><dir name="Transactions"><file name="Grid.php" hash="32b32086548f62ae4aca4baf456b9ed2"/><file name="Search.php" hash="81d57c3744530f36c37782ce9d0f3a70"/></dir><file name="Transactions.php" hash="7afe45b49353e52b432aa0392d76a08e"/></dir><dir name="System"><dir name="Config"><dir name="Braintree"><file name="Config.php" hash="eaaf6c74be4233a315d5aa5932f7c9ca"/><file name="Currency.php" hash="9ffa8a2ded53be75e88a60a024883b07"/><file name="Moduleversion.php" hash="fe3836bde24bb31c4c4585f2cd2f20ed"/><file name="Version.php" hash="ce58278a4faf965301cc2d8b2da4483c"/></dir></dir></dir></dir><dir name="Cart"><file name="Totals.php" hash="a03c441e8143896f92d02931a809f666"/></dir><dir name="Creditcard"><file name="Info.php" hash="40aa92bed04bd3744048befca2a0217a"/><file name="Threedsecure.php" hash="8eae09e8167e787f24eb80bc7ad7cd4a"/></dir><file name="Creditcard.php" hash="989678324ff3fcddcc99cbe4613019fa"/><file name="Js.php" hash="d1b2dbd2ba187100ecbbedefc633b845"/><dir name="Paypal"><file name="Info.php" hash="a0206fad8b91aa382c3ac16b9651c723"/></dir><file name="Paypal.php" hash="36294a461378cceee66e99d45753c6e1"/><file name="Saved.php" hash="74ed8e70a404a814b94f21f88c1ca737"/></dir><dir name="Helper"><file name="Data.php" hash="a5b64dd6760e881b1823adfaeb7c1501"/></dir><dir name="Model"><file name="Debug.php" hash="f3360f71e2346881f93424792ed9f209"/><file name="Observer.php" hash="176b48ac3b74bfaa3c28f4126093b49b"/><dir name="Paymentmethod"><file name="Abstract.php" hash="4043a0ac548fe0ec9acbc2dd0c57dfb4"/><file name="Creditcard.php" hash="822df144f2731ef4ceeade79f899e570"/><file name="Paypal.php" hash="445bb04b3b1d5d41383962ec8ef9daa3"/></dir><file name="Saved.php" hash="3b235b454a3692d1c3d5343e2a1c91e9"/><dir name="Source"><file name="Cctype.php" hash="d76aa6c3a4bd798e3a47695f579d21d4"/><dir name="Creditcard"><file name="CaptureAction.php" hash="6444cfc430de44f06e85bd9c8b80d77b"/><file name="PaymentAction.php" hash="a2f3f3d36a98df4d12f76b6ab77f9c47"/></dir><file name="Environment.php" hash="02567d2ddba74d06ac000b4ddb12723a"/><dir name="Paypal"><file name="Locale.php" hash="8988ca77f9c2aa2d19ff0b614a4b7621"/><file name="Paymenttype.php" hash="fe1fe4ee89d5b7a87c7c28716bb2f1cb"/></dir></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Currency.php" hash="f0cca96917d3c4c2bc05aa255544f25a"/></dir></dir></dir><dir name="Wrapper"><file name="Braintree.php" hash="aa38b6ecd7fa18c75d1bf5571cdf60fc"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="BraintreeController.php" hash="7c621fa1548c04e24bb1136bcbbe1d72"/></dir><file name="CheckoutController.php" hash="7494f5fa81cbae80778fac80fa577101"/><file name="SavedController.php" hash="036e97703c853a5bae064dd7cf5030a8"/></dir><dir name="etc"><file name="adminhtml.xml" hash="c9c940beffa0ec19e4a1499a66f7fd12"/><file name="config.xml" hash="52add3f1ba81840e9771d756b7137d22"/><file name="system.xml" hash="077114993f5d60f16e8d33221cbd19ff"/></dir><dir name="sql"><dir name="gene_braintree_setup"><file name="install-0.1.0.php" hash="7ef62b7c19b9da5990974da6edb3e77c"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><dir name="gene"><file name="braintree.xml" hash="1ded19331e4656bd31d052eb729ff7c2"/></dir></dir><dir name="template"><dir name="gene"><dir name="braintree"><dir name="creditcard"><file name="info.phtml" hash="2ae1e397b3a633dd305bc26c7b9c1065"/><file name="threedsecure.phtml" hash="ee8ad689afde041c39dd92ffa5274883"/></dir><file name="creditcard.phtml" hash="a083837c8b7d32b61336f891c5a87cb8"/><dir name="customer"><file name="methods.phtml" hash="eb5e2d8f4a0f419fcf720c12062f808a"/><file name="saved.phtml" hash="691162b89ed085599f76072226ca2307"/></dir><dir name="js"><file name="amasty.phtml" hash="652f7d6b1c9dfe6249b29ca8ee8abf82"/><file name="data.phtml" hash="7c77e2c13c9037ab993b7c7f8aa72d98"/><file name="default.phtml" hash="4fde57aa847f06bc02feaaf9097b1f57"/><file name="idev.phtml" hash="9328346d501ca6ab91451d5a99fdc287"/><file name="setup.phtml" hash="86a6da43f073b5fc75ce170a50af3bcd"/></dir><dir name="paypal"><file name="info.phtml" hash="5149b273730121e4dec3c3179820f747"/></dir><file name="paypal.phtml" hash="3c579ad7ba3290c15fcce027cdd66d16"/></dir></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="gene"><file name="braintree.xml" hash="1995e85eb47b909120ce8b9b537bf5db"/></dir></dir><dir name="template"><dir name="gene"><dir name="braintree"><dir name="creditcard"><file name="info.phtml" hash="3c5f033eb99ab8d78517ae5eb45a3a1a"/></dir><file name="creditcard.phtml" hash="0c6b7806732c336ead14fab596f1b923"/><file name="js.phtml" hash="9d51d9d573ada5f3222e29e4b9b7aaa1"/><dir name="paypal"><file name="info.phtml" hash="53fae03530369f101f5eaed49508a1ee"/></dir><dir name="transactions"><file name="index.phtml" hash="1791b6393f319616dd79c0b46e391847"/><file name="search.phtml" hash="1682ce6200681681f0ce3c848e2e6694"/></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Gene_Braintree.xml" hash="8c0ffda8566dca2f0b98a999921e3e55"/></dir></target><target name="mageweb"><dir name="js"><dir name="gene"><dir name="braintree"><file name="braintree.js" hash="4a074b2952d6e3c0052f85442b284abc"/><file name="vzero.js" hash="7e9bf97aee5e7bfe9c2d465b0609d238"/></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="images"><dir name="gene"><dir name="braintree"><file name="AE.png" hash="6b6f405105413b0723a62ee498f88bf6"/><file name="DI.png" hash="d8e3c3022dda9e723f466b8976ae428f"/><file name="JCB.png" hash="3aa9a71ed8a1d6610bbe0dfe2040e29e"/><file name="MC.png" hash="1fcd14928245139962b72f9368bdbe32"/><file name="ME.png" hash="b9389913c47b9546a67f907fcca73706"/><file name="PP.png" hash="b4946bccba574e86c9716a4986e21c36"/><file name="VI.png" hash="c9f74d1d54e61ab2c748f45a4bdface0"/><file name="card.png" hash="66e16f8c573fad93bb0d62258dce28bb"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir></dir></dir></dir></dir></dir></target><target name="magelib"><dir name="Braintree"><file name="AddOn.php" hash="07bc690cf426276dfdd802c49cfd72a3"/><file name="AddOnGateway.php" hash="ed9a94155c1c13ba37910fd48bdad40a"/><file name="Address.php" hash="1d4e7f964ed208a381b352d21fc370b8"/><file name="AddressGateway.php" hash="11716dc4ede8b7455197d08b88c91568"/><file name="ApplePayCard.php" hash="6fdbe99722514408f613c417e0e48711"/><file name="ClientToken.php" hash="f606f4bbafaea470333290be52b0030d"/><file name="ClientTokenGateway.php" hash="ede93fa63f0e96d296f315180f5ff1ad"/><file name="CoinbaseAccount.php" hash="7a4992ed13c26ad3785cf7d3455ef5fb"/><file name="Collection.php" hash="0e7d31ffcbd9780fb554186bd2c194b0"/><file name="Configuration.php" hash="6414dae20a80d926c28bd681bb535934"/><file name="CreditCard.php" hash="cf0aab2bcdcc7c231ccedc05a0f853e4"/><file name="CreditCardGateway.php" hash="3c5c3d9cee27da71e338b51d42b685ee"/><file name="CreditCardVerification.php" hash="48d6ea546914278f4bea2fefb75e7836"/><file name="CreditCardVerificationGateway.php" hash="e020dd1c26cd8c3bd7eb55eed2f72346"/><file name="CreditCardVerificationSearch.php" hash="baa6ed22471ea1f142a4195d1e36f89a"/><file name="Customer.php" hash="69d834344b93277dbeadb4ee6a881a60"/><file name="CustomerGateway.php" hash="bde59d4c6d7418fcbd87d4484384705b"/><file name="CustomerSearch.php" hash="8aacc83dac341cd9afec5a3deab17593"/><file name="Descriptor.php" hash="3f5db5e817280ce7f2fa18a205281ad9"/><file name="Digest.php" hash="9d12d067770f55b123b8498fce4478fa"/><file name="Disbursement.php" hash="589534043e466d17fede916fd7986edc"/><file name="DisbursementDetails.php" hash="ae632207d0982e288a83aed401c880d9"/><file name="Discount.php" hash="763b3f9cde0ff3af3e8795cac4097595"/><file name="DiscountGateway.php" hash="42ca6f2f11074ec18eecd1506996a393"/><dir name="Dispute"><file name="TransactionDetails.php" hash="7fdea673a1295055508f42286ad57f4e"/></dir><file name="Dispute.php" hash="2ee0f4a77b7cfec4763b55627a57e348"/><file name="EqualityNode.php" hash="cfd6aa184186233b8d6d1ec0f0e79298"/><dir name="Error"><file name="Codes.php" hash="d0d1007255af20889a4874d028ebeab2"/><file name="ErrorCollection.php" hash="e28d638db56524f5bf3609fa725e6d55"/><file name="Validation.php" hash="bf4e2198300019c52ba56f16269d66ce"/><file name="ValidationErrorCollection.php" hash="9ef25d0126a0b4f6951da5334ae6f0dc"/></dir><dir name="Exception"><file name="Authentication.php" hash="f9e13654988452cca2ac5228a80adae4"/><file name="Authorization.php" hash="5f8c017c6e9fd79a556dade8e15a72e8"/><file name="Configuration.php" hash="b50f67e8ea36cff0d9f6ad718126c6fc"/><file name="DownForMaintenance.php" hash="7fd30b1f8976ed7e38b7e9fae5c20f03"/><file name="ForgedQueryString.php" hash="6884dbae1e86767834b77c821df2db62"/><file name="InvalidSignature.php" hash="b83f5b16735cb3a8e0a8111c4f32711e"/><file name="NotFound.php" hash="f832f771d20b381c2780eb2a572b9f44"/><file name="SSLCaFileNotFound.php" hash="e927c7307bf1761814dc8a755238070d"/><file name="SSLCertificate.php" hash="d509b6a6206bd7c5563ac142dfe3801f"/><file name="ServerError.php" hash="b4645290229ab228a257047d08ef63d7"/><file name="Unexpected.php" hash="01ea2800fb91995ec2a15aee5024611e"/><file name="UpgradeRequired.php" hash="7f40b174df891cc3b3e206d1be884a58"/><file name="ValidationsFailed.php" hash="cd2d30c69911f81b55279c3d6bf88c61"/></dir><file name="Exception.php" hash="f14c94bf67206184eb3e4e7aeb4a608a"/><file name="Gateway.php" hash="8b214a63ed50539e75031caff78d4560"/><file name="Http.php" hash="5f6a9990a14684c82b6952937889412b"/><file name="Instance.php" hash="f0603b3f9213b53687e079c5621ac8f3"/><file name="IsNode.php" hash="e4b1f7bbfcbd24b1d08b97f94df592be"/><file name="KeyValueNode.php" hash="255595ec01a16906dd0c49faf67d9efb"/><dir name="MerchantAccount"><file name="AddressDetails.php" hash="1d265d864a884ebcf2504f55207cc0dd"/><file name="BusinessDetails.php" hash="c9ae627c4a4b526c2ecb0c07d70b3017"/><file name="FundingDetails.php" hash="7368f653fcbcc3d87924447b1763e616"/><file name="IndividualDetails.php" hash="68daf00759335cde82f176f0844e0d9b"/></dir><file name="MerchantAccount.php" hash="489844cfd91dcc6a53024af97b85f3c7"/><file name="MerchantAccountGateway.php" hash="6a9033758b8c02501fd835a96fc385b7"/><file name="Modification.php" hash="fcce6784af2e658affe4a67ca75d8230"/><file name="MultipleValueNode.php" hash="92700fa03011eaa9561010b3a160449c"/><file name="MultipleValueOrTextNode.php" hash="ef06bac18e2bc40974bdc0bcb854890f"/><file name="PartialMatchNode.php" hash="370c7e0ab8a445cfeef6b19ef1755f4d"/><file name="PartnerMerchant.php" hash="20c87322d040eac1abcdf12b8838ec1c"/><file name="PayPalAccount.php" hash="1bbe86a33bbf3e3620364ba0c2e9b6fe"/><file name="PayPalAccountGateway.php" hash="bdf94548085765927368c49bcf028f47"/><file name="PaymentInstrumentType.php" hash="84e2d2fcfe45cf7cf188dc46f302fac8"/><file name="PaymentMethod.php" hash="8aca88278367fcbd5404a0abae848a45"/><file name="PaymentMethodGateway.php" hash="ed81d66dcb097021c4f6518b9ea5e5cf"/><file name="PaymentMethodNonce.php" hash="a72e8ed6506327cdac92d8b082e4dd74"/><file name="PaymentMethodNonceGateway.php" hash="e8ee61d15b73bd2ef9efef8a6b5f4132"/><file name="Plan.php" hash="f73f24fcc57cfeb2e6f0e6312e531073"/><file name="PlanGateway.php" hash="8392fc6b714b30d16fe0308a1e81db4f"/><file name="RangeNode.php" hash="4ad9a92547423b3d54d69097114c3daf"/><file name="ResourceCollection.php" hash="8f437cb5014148c0e2f6049347ae795c"/><dir name="Result"><file name="CreditCardVerification.php" hash="27b965f1e197b0392879e24cccf6dd9c"/><file name="Error.php" hash="81b616e25f182c0c571ad4e9e6fbc611"/><file name="Successful.php" hash="56c6f9a3e5996d18e01a8d382cc03cde"/></dir><file name="RiskData.php" hash="dd74658f351fe8af26cee3016a076fb9"/><file name="SettlementBatchSummary.php" hash="0dcc2b5dd7071d9037cf5970fafe8668"/><file name="SettlementBatchSummaryGateway.php" hash="4ec1a7a1c8875693123430aa51410b22"/><file name="SignatureService.php" hash="4b78d3e5897e715dcc877c5f65b3cfae"/><dir name="Subscription"><file name="StatusDetails.php" hash="29e375f02150bfd7147591f0eb27cb4f"/></dir><file name="Subscription.php" hash="96db82b5b67a72d4287d79b7c691b3d7"/><file name="SubscriptionGateway.php" hash="34118ee95b83d8904a47b388cbb8cfea"/><file name="SubscriptionSearch.php" hash="1874ebe5cb42d7d2836617810cced1af"/><dir name="Test"><file name="CreditCardNumbers.php" hash="676a9100354eb679e7ca1e0f0d67293f"/><file name="MerchantAccount.php" hash="612e7e30cca364c0d14cbff3b54ebf3f"/><file name="Nonces.php" hash="89bb29ef4552037973fe04d344f657ef"/><file name="TransactionAmounts.php" hash="ed9bf1f57d871542c32d11de9e031f05"/><file name="VenmoSdk.php" hash="6ce94deccd1f968596011487c7e69cc7"/></dir><file name="TextNode.php" hash="94c95ec9645de57acace2179fef7fb43"/><dir name="Transaction"><file name="AddressDetails.php" hash="ff52a4a48248085b7ea92e992160e413"/><file name="ApplePayCardDetails.php" hash="c4dd87cd46fe7269e1bd51c867adf7cb"/><file name="CoinbaseDetails.php" hash="d19a625f8de98698b8277c25660358f0"/><file name="CreditCardDetails.php" hash="aac5eb1f5804d4f979b9c71f7b98cb36"/><file name="CustomerDetails.php" hash="e137895c646127312be44292c84a2d81"/><file name="PayPalDetails.php" hash="ede299e376bce7714838d79ca3d40842"/><file name="StatusDetails.php" hash="7c6e719c51bf13bdfd07615030100ac6"/><file name="SubscriptionDetails.php" hash="1cf1f511d1545a2e27b8d3f4bee800ca"/></dir><file name="Transaction.php" hash="9970a0fa9d6af3e543703426da99a3c4"/><file name="TransactionGateway.php" hash="37500b8a181a18375c171d4a5a4938c6"/><file name="TransactionSearch.php" hash="41dd086066fa57582161032249b3d8ee"/><file name="TransparentRedirect.php" hash="154c9850be5175a5cd1b35bdf78ae939"/><file name="TransparentRedirectGateway.php" hash="89f002df5a2abafcaa9676a3e2935c75"/><file name="UnknownPaymentMethod.php" hash="811394ea4bee98a651dc5e1cba8223da"/><file name="Util.php" hash="2cf47c3acd49da4a6c2b0a9a55701d7b"/><file name="Version.php" hash="1ebf13fcec95da846f917f74e030714b"/><file name="WebhookNotification.php" hash="f58be59156e5728f491da4235a58e994"/><file name="WebhookTesting.php" hash="c40311458bb64e37b4c08eb88df37805"/><dir name="Xml"><file name="Generator.php" hash="f82af40e5759c3d46909f3dec2498d02"/><file name="Parser.php" hash="4e6df3327a04915715333460733df93c"/></dir><file name="Xml.php" hash="dc69e05bea21e3d1185d45d53e4747db"/></dir><dir name="."><file name="Braintree.php" hash="ee3e665877882e5b5076ff51dc8111bd"/></dir><dir name="ssl"><file name="api_braintreegateway_com.ca.crt" hash="04beb23c767547e980c76eb68c7eab15"/><file name="sandbox_braintreegateway_com.ca.crt" hash="f1b529883c7c2cbb4251658f5da7b4c9"/></dir></target><target name="magelocale"><dir><dir name="en_US"><file name="Gene_Braintree.csv" hash="00ae6dc359bc0d9c48bfc90a865232a3"/></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.2.1</min><max>6.0.0</max></php><package><name/><channel>connect.magentocommerce.com/core</channel><min/><max/></package></required></dependencies>
18
+ </package>
skin/frontend/base/default/images/gene/braintree/.DS_Store ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/AE.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/DI.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/JCB.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/MC.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/ME.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/PP.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/VI.png ADDED
Binary file
skin/frontend/base/default/images/gene/braintree/card.png ADDED
Binary file