PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/Core/InfinitasPayments/Lib/InfinitasGateway.php

http://github.com/infinitas/infinitas
PHP | 364 lines | 185 code | 40 blank | 139 comment | 10 complexity | 09097e4183694cab6d5facc747d8aae5 MD5 | raw file
  1. <?php
  2. class InfinitasGateway {
  3. public static $PENDING = 0;
  4. public static $PAID = 1;
  5. public static $CANCELED = -1;
  6. public static $ERROR = -2;
  7. /**
  8. * Instance of the payment class
  9. *
  10. * @var PaymentSocket
  11. */
  12. protected $_Payment;
  13. /**
  14. * The order index
  15. *
  16. * @var integer
  17. */
  18. protected $_orderIndex = 0;
  19. /**
  20. * The orders for this payment
  21. *
  22. * Some processors allow making many transactions at a time such as PayPal, so we can collect details
  23. * for multiple orders here for processing
  24. *
  25. * @var array
  26. */
  27. protected $_orders = array();
  28. /**
  29. * The default fields that are available when processing payments.
  30. *
  31. * This is a generic list of what fields that can be used that the payment gateway will be expecting
  32. *
  33. * @var array
  34. */
  35. protected $_fields = array(
  36. 'user' => array(
  37. 'id' => null,
  38. 'salutation' => null,
  39. 'email' => null,
  40. 'username' => null,
  41. 'full_name' => null,
  42. 'first_name' => null,
  43. 'middle_name' => null,
  44. 'last_name' => null,
  45. 'suffix' => null,
  46. 'phone' => null,
  47. ),
  48. 'address' => array(
  49. 'address_1' => null,
  50. 'address_2' => null,
  51. 'city' => null,
  52. 'state' => null,
  53. 'post_code' => null,
  54. 'country_code' => null,
  55. 'country' => null,
  56. ),
  57. 'item' => array(
  58. 'name' => null,
  59. 'description' => null,
  60. 'selling' => 0,
  61. 'quantity' => 0,
  62. 'tax' => 0
  63. ),
  64. 'cc' => array(
  65. 'type' => null,
  66. 'number' => null,
  67. 'expires' => null,
  68. 'cvv2' => null
  69. ),
  70. 'order' => array(
  71. 'custom' => null,
  72. 'invoice_number' => null,
  73. 'notify_url' => null,
  74. 'currency_code' => null,
  75. 'total' => 0,
  76. 'shipping' => 0,
  77. 'handling' => 0,
  78. 'insurance' => 0,
  79. 'tax' => 0,
  80. 'user' => array(),
  81. 'address' => array(),
  82. 'items' => array(),
  83. 'cc' => array()
  84. )
  85. );
  86. /**
  87. * Constructor
  88. *
  89. * @param string $provider The provider to use
  90. * @param string $type the type of transaction being done
  91. * @param array $config configs that will be passed to the provider class
  92. *
  93. * @return void
  94. */
  95. public function __construct($provider = null) {
  96. if ($provider) {
  97. $this->provider($provider);
  98. }
  99. }
  100. /**
  101. * Specify the payment provider
  102. *
  103. * @param string $provider
  104. * @param string $type
  105. *
  106. * @return InfinitasGateway
  107. */
  108. public function provider($provider) {
  109. $this->_Payment = null;
  110. $this->_provider = $provider;
  111. return $this;
  112. }
  113. /**
  114. * Complete the order
  115. *
  116. * This finalises the details for the order and increments the orderIndex counter so the next order
  117. * can begin.
  118. *
  119. *
  120. *
  121. * @return InfinitasGateway
  122. */
  123. public function complete() {
  124. if (empty($this->_orders[$this->currentOrderindex()])) {
  125. return $this;
  126. }
  127. $order = $this->_orders[$this->currentOrderindex()];
  128. $order = array_merge($this->_fields['order'], $order);
  129. $order['user'] = array_merge($this->_fields('user'), $order['user']);
  130. $order['address'] = array_merge($this->_fields('address'), $order['address']);
  131. $items = $order['items'];
  132. $subtotal = array_sum(Hash::extract($items, '{n}.subtotal'));
  133. $tax = array_sum(Hash::extract($items, '{n}.tax_subtotal'));
  134. $total = array_sum(array(
  135. $subtotal,
  136. $tax,
  137. $order['shipping'],
  138. $order['handling'],
  139. $order['insurance']
  140. ));
  141. $this->_orders[$this->currentOrderindex()] = $order;
  142. $this->_addToOrder('subtotal', $subtotal);
  143. $this->_addToOrder('tax', $tax);
  144. $this->_addToOrder('total', $total);
  145. $this->_orderIndex++;
  146. return $this;
  147. }
  148. /**
  149. * Process a payment
  150. *
  151. * Once all the details have been added to the orders this method can be called which will dispatch
  152. * the details to the selected payment class for processing.
  153. *
  154. * It will return what is sent from the payment gateway class
  155. *
  156. * The returl_url and cancel_url will be caught by the InfinitasPaymentComponent no matter what plugin / controller
  157. * is loaded. If the plugin doing requesting the payment wishes to handle the transaction manually the
  158. * methods can be defined in the same controller that generates the initial request.
  159. *
  160. * @return array
  161. */
  162. public function prepare() {
  163. return $this->_providerClass()->sendRequest('prepare', array(
  164. 'return_url' => InfinitasRouter::url(array(
  165. 'action' => 'infinitas_payment_completed'
  166. )),
  167. 'cancel_url' => InfinitasRouter::url(array(
  168. 'action' => 'infinitas_payment_canceled'
  169. )),
  170. 'orders' => $this->complete()->orders()
  171. ));
  172. }
  173. /**
  174. * Get the status of a transaction
  175. *
  176. * @param array $data
  177. *
  178. * @return array
  179. */
  180. public function status(array $data) {
  181. $return = $this->_providerClass()->sendRequest('status', $data);
  182. ClassRegistry::init('InfinitasPayments.InfinitasPaymentLog')->getTransactionDetails($return);
  183. return $return;
  184. }
  185. /**
  186. * Finalise a transaction
  187. *
  188. * When a transaction is finalised the details are saved to the log
  189. *
  190. * @param array $data
  191. *
  192. * @return array
  193. */
  194. public function finalise(array $data) {
  195. $return = $this->_providerClass()->sendRequest('finalise', $data);
  196. ClassRegistry::init('InfinitasPayments.InfinitasPaymentLog')->saveTransactionDetails($return);
  197. return $return;
  198. }
  199. /**
  200. * Get all the orders
  201. *
  202. * @return array
  203. */
  204. public function orders() {
  205. return $this->_orders;
  206. }
  207. /**
  208. * Get the current order index
  209. *
  210. * @return integer
  211. */
  212. public function currentOrderindex() {
  213. return $this->_orderIndex;
  214. }
  215. /**
  216. * Get the count of items in the order specified by the order index
  217. *
  218. * Pass null to check the current order
  219. *
  220. * @param null|integer $orderIndex the order index to check
  221. *
  222. * @return integer
  223. */
  224. public function itemCount($orderIndex = null) {
  225. if ($orderIndex === null) {
  226. $orderIndex = $this->currentOrderindex();
  227. }
  228. if (!empty($this->_orders[$orderIndex]['items'])) {
  229. return count($this->_orders[$orderIndex]['items']);
  230. }
  231. return 0;
  232. }
  233. /**
  234. * Add an item to the order
  235. *
  236. * @param array $data
  237. *
  238. * @return InfinitasGateway
  239. */
  240. public function item(array $data) {
  241. $data = array_merge($this->_fields(__FUNCTION__), array_intersect_key($data, $this->_fields(__FUNCTION__)));
  242. $data['subtotal'] = $data['quantity'] * $data['selling'];
  243. $data['tax_subtotal'] = $data['quantity'] * $data['tax'];
  244. $this->_orders[$this->currentOrderindex()]['items'][] = $data;
  245. return $this;
  246. }
  247. /**
  248. * Magic method for adding details to an order
  249. *
  250. * @param string $name
  251. * @param array $data
  252. *
  253. * @return array
  254. */
  255. public function __call($name, $data) {
  256. $data = current($data);
  257. if (stristr($name, 'url') !== false) {
  258. return $this->_addToOrder($name, InfinitasRouter::url($data));
  259. }
  260. if (is_array($data)) {
  261. $data = array_merge($this->_fields($name), $data);
  262. return $this->_addToOrder($name, array_intersect_key($data, $this->_fields($name)));
  263. }
  264. $floats = array(
  265. 'shipping',
  266. 'handling',
  267. 'insurance',
  268. 'subtotal',
  269. 'tax_subtotal',
  270. 'tax',
  271. 'total'
  272. );
  273. if (in_array($name, $floats)) {
  274. return $this->_addToOrder($name, (float)$data);
  275. }
  276. return $this->_addToOrder($name, (string)$data);
  277. }
  278. /**
  279. * Generic add data to the order
  280. *
  281. * @param string $key the key of the data to add
  282. * @param string|integer|float|array $data the data to add
  283. *
  284. * @return InfinitasGateway
  285. */
  286. protected function _addToOrder($key, $data) {
  287. $this->_orders[$this->currentOrderindex()][Inflector::underscore($key)] = $data;
  288. return $this;
  289. }
  290. /**
  291. * Get the default fields for the selected type
  292. *
  293. * @param type $type
  294. *
  295. * @return array
  296. */
  297. protected function _fields($type) {
  298. return $this->_fields[$type];
  299. }
  300. /**
  301. * Get the provider class
  302. *
  303. * Load up the required class and configs from the database and initialise the class. Processing only
  304. * occurs the first time this method is called after setting / chaning the provider
  305. *
  306. * @return PaymentSocket
  307. */
  308. protected function _providerClass() {
  309. if (empty($this->_Payment)) {
  310. if (!$this->_provider) {
  311. throw new InvalidProviderException();
  312. }
  313. $paymentMethod = ClassRegistry::init('InfinitasPayments.InfinitasPaymentMethod')->find('config', $this->_provider);
  314. $provider = Configure::read('InfinitasPayments.Provider.' . $paymentMethod['provider']);
  315. App::uses($provider['class'], 'InfinitasPayments.Lib/Providers/' . Inflector::classify($provider['provider']));
  316. $this->_Payment = new $provider['class'](array(
  317. 'live' => $paymentMethod['live'],
  318. 'sandbox' => $paymentMethod['sandbox'],
  319. 'debug' => Configure::read('debug') || $paymentMethod['testing'],
  320. ));
  321. }
  322. return $this->_Payment;
  323. }
  324. }